📌  相关文章
📜  总和正好为 K 的最短子序列

📅  最后修改于: 2022-05-13 01:56:04.441000             🧑  作者: Mango

总和正好为 K 的最短子序列

给定一个大小为N的数组Arr[]和一个整数K ,任务是找到总和正好为K的最短子序列的长度。

例子:

朴素方法:解决上述问题的最基本方法之一是使用递归生成所有子集,并选择具有最小大小且恰好和K的子集。

时间复杂度: O (N * 2 N )。
辅助空间 O(1)

有效方法:上述问题可以通过以下方式在动态规划中有效地解决。

请按照以下步骤实施该方法:

  1. 从数组的开头迭代。
  2. 对于每个元素,有两个选择:要么选择元素,要么不选择。
  3. 如果第 i 个元素的值大于具有子序列和K所需的总和(例如X ),则不能包含它。
  4. 否则,请执行以下操作:
    • 选择第i 个元素,将所需的总和更新为(X-Arr[i])并递归地对步骤 5 中的下一个索引执行相同操作。
    • 不要在子序列中插入元素并递归调用下一个元素。
    • 将这两者之间的最小值存储在dp[][]数组中。
  5. 在每个递归调用中:
    • 如果所需的总和为 0,则将子序列的长度存储在 dp[][] 数组中。
    • 如果它已经为iX的相同值计算过,则它已经计算过,则返回相同的值。
    • 如果无法从该状态获得恰好K的子序列和,则返回-1
  6. 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)