zoukankan      html  css  js  c++  java
  • [Coding Made Simple] Subset Sum Problem

    Given a set of non negative integers and a target value, find if there exists a subset in the given set whose sum is target.

     Solution 1. Enumerate all possible subsets and check if their sum is the target

      The runtime of this solution is O(2^n).  This enumeration algorithm is similar with the problem Subsets. The difference is 

    that Subsets has to get all possible subsets. But this problem can terminate the check earlier if for one element arr[startIdx]

    including it in the subset and not including it both returns a false check. This is correct because for any subsets, it either has

    arr[startIdx] or does not have it.

     1 import java.util.Arrays;
     2 public class Subsets {
     3     public boolean findIfExistSubset(int[] arr, int target){
     4         if(target == 0){
     5             return true;
     6         }
     7         if(arr == null || arr.length == 0 || target < 0){
     8             return false;
     9         }
    10         Arrays.sort(arr);
    11         if(target < arr[0] || target >= arr[arr.length - 1] * arr.length){
    12             return false;
    13         }
    14         return helper(arr, 0, 0, target);
    15     }
    16     private boolean helper(int[] arr, int startIdx, int currSum, int target){
    17         if(currSum == target){
    18             return true;
    19         }
    20         if(currSum > target){
    21             return false;
    22         }
    23         if(startIdx >= arr.length){
    24             return false;
    25         }
    26         currSum += arr[startIdx];
    27         if(helper(arr, startIdx + 1, currSum, target)){
    28             return true;
    29         }
    30         currSum -= arr[startIdx];
    31         if(helper(arr, startIdx + 1, currSum, target)){
    32             return true;
    33         }
    34         return false;
    35     }
    36 }

    Solution 2. Dynamic Programming, runtime is O(arr.length * target), space complexity is O(arr.length * target)

     State: T[i][j]: if total sum j can be found from a subset from arr[0......i - 1];

    Function: T[i][j] = T[i - 1][j] || T[i - 1][j - arr[i - 1]],  if j >= arr[i - 1];  if the current target j is >= arr[i - 1], it means that we can possibly select arr[i - 1] as part of the subset. T[i][j] will be either not selecting arr[i - 1] (T[i - 1][j]) or selecting arr[i - 1] (T[i - 1][j - arr[i - 1]]);

        T[i][j] = T[i - 1][j], if j < arr[i - 1]; if j < arr[i - 1], it means we can't select arr[i - 1].

         i - 1 here indicates that for each element in arr[], it can only be selected at most once.  

    Init: T[i][0] = true for i in [0, arr.length]; this means when the target is 0, then for set arr[0.... i - 1] we always have the empty set that sums up to 0.

    Answer: T[arr.length][target]

     1 public boolean findIfExistSubsetDp(int[] arr, int target){
     2     boolean[][] T = new boolean[arr.length + 1][target + 1];
     3     for(int i = 0; i <= arr.length; i++){
     4         T[i][0] = true;
     5     }
     6     for(int i = 1; i <= arr.length; i++){
     7         for(int j = 1; j <= target; j++){
     8             if(j >= arr[i - 1]){
     9                 T[i][j] = T[i - 1][j] || T[i - 1][j - arr[i - 1]];
    10             }
    11             else{
    12                 T[i][j] = T[i - 1][j];
    13             }
    14         }            
    15     }
    16     return T[arr.length][target];
    17 }

    Optimized Dp solution with O(target) space

     1 public boolean findIfExistSubsetDp(int[] arr, int target){
     2     boolean[][] T = new boolean[2][target + 1];
     3     T[0][0] = true;
     4     for(int i = 1; i <= arr.length; i++){
     5         T[i % 2][0] = true;
     6         for(int j = 1; j <= target; j++){
     7             if(j >= arr[i - 1]){
     8                 T[i % 2][j] = T[(i - 1) % 2][j] || T[(i - 1) % 2][j - arr[i - 1]];
     9             }
    10             else{
    11                 T[i % 2][j] = T[(i - 1) % 2][j];
    12             }
    13         }            
    14     }
    15     return T[arr.length % 2][target];
    16 }

     Follow up question: 

    What about if we change the condition so that each element in the input set can be selected more than once? 

    The change needs to make is that when the current element arr[i - 1] can be selected, we don't exclude it from

    being selected again.

    T[i][j] = T[i - 1][j] || T[i][j - arr[i - 1]];  

     1 public boolean findIfExistSubsetDp(int[] arr, int target){
     2     boolean[][] T = new boolean[arr.length + 1][target + 1];
     3      for(int i = 0; i <= arr.length; i++){
     4          T[i][0] = true;
     5      }
     6      for(int i = 1; i <= arr.length; i++){
     7          for(int j = 1; j <= target; j++){
     8              if(j >= arr[i - 1]){
     9                  T[i][j] = T[i - 1][j] || T[i][j - arr[i - 1]];
    10              }
    11              else{
    12                  T[i][j] = T[i - 1][j];
    13              }
    14          }            
    15     }
    16     return T[arr.length][target];
    17 }

    Related Problems

    Subsets

    Backpack(Knapsack) problems

  • 相关阅读:
    蚂蚁变大象:浅谈常规网站是如何从小变大的(八)(转)
    蚂蚁变大象:浅谈常规网站是如何从小变大的(七)(转)
    蚂蚁变大象:浅谈常规网站是如何从小变大的(六)(转)
    蚂蚁变大象:浅谈常规网站是如何从小变大的(五)(转)
    蚂蚁变大象:浅谈常规网站是如何从小变大的(四)(转)
    蚂蚁变大象:浅谈常规网站是如何从小变大的(三)(转)
    简单的Poc Exp编写(上)
    kali渗透windowsXP过程
    [W3bSafe]Metasploit溢出渗透内网主机辅助脚本
    WannaCry勒索病毒全解读,权威修复指南大集合
  • 原文地址:https://www.cnblogs.com/lz87/p/7284541.html
Copyright © 2011-2022 走看看