总和正好为 K 的最短子序列
给定一个大小为N的数组Arr[]和一个整数K ,任务是找到总和正好为K的最短子序列的长度。
例子:
Input: N = 5, K = 4, Arr[] = {1, 2, 2, 3, 4}
Output: 1
Explanation: Here, one can choose the last month and can get 4 working hours.
Input: N = 3, K = 2, Arr[] = {1, 3, 5}
Output: -1
Explanation: Here, we can not get exactly 2 hours of work from any month.
朴素方法:解决上述问题的最基本方法之一是使用递归生成所有子集,并选择具有最小大小且恰好和K的子集。
时间复杂度: O (N * 2 N )。
辅助空间: O(1)
有效方法:上述问题可以通过以下方式在动态规划中有效地解决。
On each index there are two choices: either to include the element in the subsequence or not. To efficiently calculate this, use a two dimensional dp[][] array where dp[i][j] stores the minimum length of subsequence with sum j up to ith index.
请按照以下步骤实施该方法:
- 从数组的开头迭代。
- 对于每个元素,有两个选择:要么选择元素,要么不选择。
- 如果第 i 个元素的值大于具有子序列和K所需的总和(例如X ),则不能包含它。
- 否则,请执行以下操作:
- 选择第i 个元素,将所需的总和更新为(X-Arr[i])并递归地对步骤 5 中的下一个索引执行相同操作。
- 不要在子序列中插入元素并递归调用下一个元素。
- 将这两者之间的最小值存储在dp[][]数组中。
- 在每个递归调用中:
- 如果所需的总和为 0,则将子序列的长度存储在 dp[][] 数组中。
- 如果它已经为i和X的相同值计算过,则它已经计算过,则返回相同的值。
- 如果无法从该状态获得恰好K的子序列和,则返回-1 。
- dp[0][K]处的最终值将表示最小子序列长度。
下面是上述方法的实现:
C++
// C++ code for the above approach:
#include
using namespace std;
// Function which returns smallest
// Subset size which sums exactly K
// Or else returns -1
// If there is no such subset
int minSize(vector >& dp,
int i, vector& arr,
int k, int n)
{
// Size of empty subset is zero
if (k == 0)
return 0;
// If the end of the array is reached
// and k is not reduced to zero
// then there is no subset
// gor current value of k
if (i == n)
return -1;
// If some value of K is present
// and it is required to make a choice
// either to pick the ith element or
// unpick it, and if it is already
// computed, Return the answer directly
if (dp[i][k] != 0)
return dp[i][k];
int x, y, maxi;
maxi = INT_MAX;
// Initialize with maximum value since
// it is required to find
// the smallest subset
x = y = maxi;
// If the ith element is less than
// or equal to k than
// it can be a part of subset
if (arr[i] <= k) {
// Check whether there is a subset
// for ( k - arr[i])
int m = minSize(dp, i + 1, arr,
k - arr[i], n);
// Check whether m is -1 or not
if (m != -1) {
// If m is not equal to -1
// that means there exists a subset
// for the value ( k - arr[i] )
// update the subset size
x = min(x, m + 1);
}
}
// Exclude the current element and
// check whether there is a subset for K
// by trying the rest of the combinations
int m = minSize(dp, i + 1, arr, k, n);
// Check whether m is not equal to -1
if (m != -1) {
// If m is not equal to -1 than
// a subset is found for value
// of K so update the
// size of the subset
y = min(y, m);
}
// If both x and y are equal
// to maximum value, which means there
// is no subset for the current value of K
// either including the current element
// or excluding the current element
// In that case store -1 or else
// store the minimum of ( x, y)
// since we need the smallest subset
return (dp[i][k]
= (x == maxi and y == maxi) ? -1
: min(x, y));
}
// Function to calculate the
// required length of subsequence
int seqLength(vector& arr, int k)
{
int n = arr.size();
// Initialize the dp vector with 0
// in order to indicate that there
// is no computed answer for any
// of the sub problems
vector > dp(n,
vector(k + 1,
0));
return minSize(dp, 0, arr, k, n);
}
// Driver Code
int main()
{
int N = 5;
int K = 4;
vector arr = { 1, 2, 2, 3, 4 };
// Function call
cout << seqLength(arr, K) << endl;
return 0;
}
Java
// Java Program of the above approach.
import java.util.*;
class GFG {
// Function which returns smallest
// Subset size which sums exactly K
// Or else returns -1
// If there is no such subset
static int minSize(int[][] dp, int i, int[] arr, int k,
int n)
{
// Size of empty subset is zero
if (k == 0)
return 0;
// If the end of the array is reached
// and k is not reduced to zero
// then there is no subset
// gor current value of k
if (i == n)
return -1;
// If some value of K is present
// and it is required to make a choice
// either to pick the ith element or
// unpick it, and if it is already
// computed, Return the answer directly
if (dp[i][k] != 0)
return dp[i][k];
int x = 0, y = 0, maxi = Integer.MAX_VALUE;
// Initialize with maximum value since
// it is required to find
// the smallest subset
x = y = maxi;
// If the ith element is less than
// or equal to k than
// it can be a part of subset
if (arr[i] <= k) {
// Check whether there is a subset
// for ( k - arr[i])
int m1 = minSize(dp, i + 1, arr, k - arr[i], n);
// Check whether m is -1 or not
if (m1 != -1) {
// If m is not equal to -1
// that means there exists a subset
// for the value ( k - arr[i] )
// update the subset size
x = Math.min(x, m1 + 1);
}
}
// Exclude the current element and
// check whether there is a subset for K
// by trying the rest of the combinations
int m2 = minSize(dp, i + 1, arr, k, n);
// Check whether m is not equal to -1
if (m2 != -1) {
// If m is not equal to -1 than
// a subset is found for value
// of K so update the
// size of the subset
y = Math.min(y, m2);
}
// If both x and y are equal
// to maximum value, which means there
// is no subset for the current value of K
// either including the current element
// or excluding the current element
// In that case store -1 or else
// store the minimum of ( x, y)
// since we need the smallest subset
return (dp[i][k] = (x == maxi && y == maxi)
? -1
: Math.min(x, y));
}
// Function to calculate the
// required length of subsequence
static int seqLength(int[] arr, int k)
{
int n = arr.length;
// Initialize the dp vector with 0
// in order to indicate that there
// is no computed answer for any
// of the sub problems
int[][] dp = new int[n][k + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j < k + 1; j++) {
dp[i][j] = 0;
}
}
return minSize(dp, 0, arr, k, n);
}
// Driver Code
public static void main(String args[])
{
int N = 5;
int K = 4;
int[] arr = { 1, 2, 2, 3, 4 };
// Function call
System.out.print(seqLength(arr, K));
}
}
// This code is contributed by code_hunt.
Python3
# python3 code for the above approach:
INT_MAX = 2147483647
# Function which returns smallest
# Subset size which sums exactly K
# Or else returns -1
# If there is no such subset
def minSize(dp, i, arr, k, n):
# Size of empty subset is zero
if (k == 0):
return 0
# If the end of the array is reached
# and k is not reduced to zero
# then there is no subset
# gor current value of k
if (i == n):
return -1
# If some value of K is present
# and it is required to make a choice
# either to pick the ith element or
# unpick it, and if it is already
# computed, Return the answer directly
if (dp[i][k] != 0):
return dp[i][k]
maxi = INT_MAX
# Initialize with maximum value since
# it is required to find
# the smallest subset
x = y = maxi
# If the ith element is less than
# or equal to k than
# it can be a part of subset
if (arr[i] <= k):
# Check whether there is a subset
# for ( k - arr[i])
m = minSize(dp, i + 1, arr, k - arr[i], n)
# Check whether m is -1 or not
if (m != -1):
# If m is not equal to -1
# that means there exists a subset
# for the value ( k - arr[i] )
# update the subset size
x = min(x, m + 1)
# Exclude the current element and
# check whether there is a subset for K
# by trying the rest of the combinations
m = minSize(dp, i + 1, arr, k, n)
# Check whether m is not equal to -1
if (m != -1):
# If m is not equal to -1 than
# a subset is found for value
# of K so update the
# size of the subset
y = min(y, m)
# If both x and y are equal
# to maximum value, which means there
# is no subset for the current value of K
# either including the current element
# or excluding the current element
# In that case store -1 or else
# store the minimum of ( x, y)
# since we need the smallest subset
dp[i][k] = -1 if (x == maxi and y == maxi) else min(x, y)
return dp[i][k]
# Function to calculate the
# required length of subsequence
def seqLength(arr, k):
n = len(arr)
# Initialize the dp vector with 0
# in order to indicate that there
# is no computed answer for any
# of the sub problems
dp = [[0 for _ in range(K+1)] for _ in range(n)]
return minSize(dp, 0, arr, k, n)
# Driver Code
if __name__ == "__main__":
N = 5
K = 4
arr = [1, 2, 2, 3, 4]
# Function call
print(seqLength(arr, K))
# This code is contributed by rakeshsahni
C#
// C# code for the above approach:
using System;
class GFG {
// Function which returns smallest
// Subset size which sums exactly K
// Or else returns -1
// If there is no such subset
static int minSize(int[, ] dp, int i, int[] arr, int k,
int n)
{
// Size of empty subset is zero
if (k == 0)
return 0;
// If the end of the array is reached
// and k is not reduced to zero
// then there is no subset
// gor current value of k
if (i == n)
return -1;
// If some value of K is present
// and it is required to make a choice
// either to pick the ith element or
// unpick it, and if it is already
// computed, Return the answer directly
if (dp[i, k] != 0)
return dp[i, k];
int x = 0, y = 0, maxi = Int32.MaxValue;
// Initialize with maximum value since
// it is required to find
// the smallest subset
x = y = maxi;
// If the ith element is less than
// or equal to k than
// it can be a part of subset
if (arr[i] <= k) {
// Check whether there is a subset
// for ( k - arr[i])
int m1 = minSize(dp, i + 1, arr, k - arr[i], n);
// Check whether m is -1 or not
if (m1 != -1) {
// If m is not equal to -1
// that means there exists a subset
// for the value ( k - arr[i] )
// update the subset size
x = Math.Min(x, m1 + 1);
}
}
// Exclude the current element and
// check whether there is a subset for K
// by trying the rest of the combinations
int m2 = minSize(dp, i + 1, arr, k, n);
// Check whether m is not equal to -1
if (m2 != -1) {
// If m is not equal to -1 than
// a subset is found for value
// of K so update the
// size of the subset
y = Math.Min(y, m2);
}
// If both x and y are equal
// to maximum value, which means there
// is no subset for the current value of K
// either including the current element
// or excluding the current element
// In that case store -1 or else
// store the minimum of ( x, y)
// since we need the smallest subset
return (dp[i, k] = (x == maxi && y == maxi)
? -1
: Math.Min(x, y));
}
// Function to calculate the
// required length of subsequence
static int seqLength(int[] arr, int k)
{
int n = arr.Length;
// Initialize the dp vector with 0
// in order to indicate that there
// is no computed answer for any
// of the sub problems
int[, ] dp = new int[n, k + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j < k + 1; j++) {
dp[i, j] = 0;
}
}
return minSize(dp, 0, arr, k, n);
}
// Driver Code
public static void Main()
{
int N = 5;
int K = 4;
int[] arr = { 1, 2, 2, 3, 4 };
// Function call
Console.WriteLine(seqLength(arr, K));
}
}
// This code is contributed by Samim Hossain Mondal.
Javascript
1
时间复杂度: O(N * K)
辅助空间: O(N * K)