Skip to main content

Subset Sum Problem - Medium


Problem : Given a set of integers A, find out if there is a subset of A which add up to a particular integer K.

Formally called the Subset Sum Problem, we are given an NP-Complete problem. To solve this, we have to exhaustively search every subset and verify if they add up to an integer K.

Let's begin with a Brute force DFS search, we're going to construct subsets incrementally until the sum exceeds K. The elements are assumed sorted in the increasing order.

def subset_sum(lst,K):
lst.sort()
sz = len(lst)
def subset_sum_helper(index,s):
if index == sz or s >= K : return s == K
return subset_sum_helper(index + 1, s) or subset_sum_helper(index + 1, s + lst[index])
return subset_sum_helper(0 , 0 )
view raw Subset Sum DFS hosted with ❤ by GitHub

So we perform a DFS trying to perform every combination of the elements in the set. The recursive function either will include an element in the sum or exclude it. The guard prunes off DFS paths that exceed the sum required.

There is an efficient method for this, using Dynamic Programming. Essentially, we start with a single element, add the next element together to get the new sums possible. These new sums will be the input for the next iteration. I'll explain with an example, say we have {a,b,c}


  • You start with a set, lets call it partial_sums = {0}. For each element in the partial_sums we add a to the set. So after one iteration we have {0,0+a} ie {0,a}
  • Now for b, repeat the procedure. This gives us partial_sums =  {0,a,b,a+b}
  • Finally, c gives us {0,a,b,c,a+c,b+c,a+b+c}
  • Note : if any sum exceeds K we don't need to add it to the set (assuming the initial set was sorted, since the sum can only increase.)
Here's the solution implemented.

def subset_sum_dp(lst,K):
ways = {0}
lst.sort()
for v in lst:
t = set()
for w in ways:
nv = v+w
if nv == K : return True
if nv < K:
t.add(v+w)
ways.update(t)
return False
view raw Subset Sum DP hosted with ❤ by GitHub

Here's the complete gist

Comments

Popular posts from this blog

Find Increasing Triplet Subsequence - Medium

Problem - Given an integer array A[1..n], find an instance of i,j,k where 0 < i < j < k <= n and A[i] < A[j] < A[k]. Let's start with the obvious solution, bruteforce every three element combination until we find a solution. Let's try to reduce this by searching left and right for each element, we search left for an element smaller than the current one, towards the right an element greater than the current one. When we find an element that has both such elements, we found the solution. The complexity of this solution is O(n^2). To reduce this even further, One can simply apply the longest increasing subsequence algorithm and break when we get an LIS of length 3. But the best algorithm that can find an LIS is O(nlogn) with O( n ) space . An O(nlogn) algorithm seems like an overkill! Can this be done in linear time? The Algorithm: We iterate over the array and keep track of two things. The minimum value iterated over (min) The minimum increa...

Dijkstra's algorithm - Part 1 - Tutorial

This will be a 3 Part series of posts where I will be implementing the Dijkstra's Shortest Path algorithm in Python. The three parts will be 1) Representing the Graph 2) Priority Queue 3) The Algorithm To represent a graph we'll be using an  Adjacency List . Another alternative is using an Adjacency Matrix, but for a sparse graph an Adjacency List is more efficient. Adjacency List An Adjacency List is usually represented as a HashTable (or an Array) where an entry at `u` contains a Linked List. The Linked List contains `v` and optionally another parameter `w`. Here `u` and `v` are node(or vertex) labels and `w` is the weight of the edge. By Traversing the linked list we obtain the immediate neighbours of `u`. Visually, it looks like this. For implementing this in Python, we'll be using the dict()  for the main HashTable. For the Linked List we can use a list of 2 sized tuples (v,w).  Sidenote: Instead of a list of tuples, you can use a dict(), ...

Find the Quadruplets - Hard

Problem - Given 4 arrays A,B,C,D. Find out if there exists an instance where A[i] + B[j] + C[k] + D[l] = 0 Like the Find the Triple problem, we're going to develop 4 algorithms to solve this. Starting with the naive O(n^4) solution. Then we proceed to eliminate the inner-most loop with a Binary Search, reducing the complexity to O(n^3 logn) Now, we replace the last 2 loops with the left-right traversal we did in the previous 3 posts. Now the complexity is O(n^3). Finally, we reduce the complexity to O(n^2 logn) at the cost of O(n^2) Space Complexity. We store every combination of A[i] + B[j] and store it in AB[]. Similarly we make CD[] out of C[i] + D[j]. So, AB = A x B CD = C x D We then sort AB and CD (which costs O(n^2 log(n^2)) ~ O(n^2 logn) ) and then run a left-right linear Algorithm on AB and CD. (Note : Their size is of the order O(n^2)) So the overall complexity is due to sorting the large array of size n^2. which is O(n^2 logn).