[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

时间: 2024-08-29 12:33:42

[Coding Made Simple] Subset Sum Problem的相关文章

[Coding Made Simple] Maximum Sum Subsequence Non-adjacent

Given an array of positive number, find maximum sum subsequence such that elements in this subsequence are not adjacent to each other. Recursive formula: f(n) = Math.max{f(n - 1), f(n - 2) + arr[n - 1]}. Dynamic programming is used to get rid of the

[Coding Made Simple] Box Stacking

Given boxes of different dimensions, stack them on top of each other to get maximum height such that box on top has strictly less length and width than box under it. Algorithm. 1. get all the box permutation with each permutation's length >= width; s

hdu 4975 A simple Gaussian elimination problem.(网络流,判断矩阵是否存在)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975 Problem Description Dragon is studying math. One day, he drew a table with several rows and columns, randomly wrote numbers on each elements of the table. Then he counted the sum of each row and col

hdoj 4971 A simple brute force problem. 【最大闭合权 --&gt; 最小割】

题目:hdoj 4971 A simple brute force problem. 题意:给出 n 个任务和 m 项技术,完成某个任务需要其中几项技术,完成某个任务有奖金,学习某个技术需要钱,技术之间有父子关系,某项技术可能需要先学习其他技术,然后问你选择做那些任务获得收益最大? 分析:看题意的黑体字部分,就是一个标准的闭合权问题,这个题目的关键忽悠点在于技术之间的关系,导致很多人想到了dp以及树形dp. 其实就是一个闭合权问题模板,官方题解说如果技术之间存在相互的关系需要缩点,其实不用缩点也

HDU 4971 A simple brute force problem.(dp)

HDU 4971 A simple brute force problem. 题目链接 官方题解写的正解是最大闭合权,但是比赛的时候用状态压缩的dp也过掉了- -,还跑得挺快 思路:先利用dfs预处理出每个项目要完成的技术集合,那么dp[i][j]表示第i个项目,已经完成了j集合的技术,由于j这维很大,所以利用map去开数组 代码: #include <cstdio> #include <cstring> #include <algorithm> #include &l

【最小割】HDU 4971 A simple brute force problem.

说是最大权闭合图.... 比赛时没敢写.... 题意 一共有n个任务,m个技术 完成一个任务可盈利一些钱,学习一个技术要花费钱 完成某个任务前需要先学习某几个技术 但是可能在学习一个任务前需要学习另几个任务 求最多能赚多少钱咯 先将缩点将需要一起学掉的技术缩成一个点 建s--任务 权值为该任务盈利多少钱 建技术(缩点后)-t 权值为学习这技术的花费(总) 任务-技术 (完成该任务所需的每个技术都需要建边)权值为INF #include<stdio.h> #include<stdlib.h

HDU - 4971 A simple brute force problem. (DP)

Problem Description There's a company with several projects to be done. Finish a project will get you profits. However, there are some technical problems for some specific projects. To solve the problem, the manager will train his employee which may

HDU 4975 A simple Gaussian elimination problem.(网络最大流)

http://acm.hdu.edu.cn/showproblem.php?pid=4975 A simple Gaussian elimination problem. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 669    Accepted Submission(s): 222 Problem Description Drag

HDOJ 4975 A simple Gaussian elimination problem.

和HDOJ4888是一样的问题,最大流推断多解 1.把ISAP卡的根本出不来结果,仅仅能把全为0或者全为满流的给特判掉...... 2.在残量网络中找大于2的圈要用一种类似tarjian的方法从汇点開始找,推断哪些点没有到汇点 A simple Gaussian elimination problem. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submiss