💡 Memoization caches results of subproblems to avoid recomputation, drastically improving efficiency over brute force.
Intuition
Store results of recursive calls for each index and target to reuse them instead of recomputing.
Algorithm
- Initialize a memo dictionary to store results for (index, target).
- Recursively explore including or excluding current element.
- Before recursion, check if result is cached and return if so.
- Return true if any path leads to target sum.
💡 Memoization prunes the recursion tree by remembering past results.
Recurrence:f(i, w) = f(i-1, w) OR f(i-1, w - nums[i-1]) if w >= nums[i-1]
def subset_sum(nums, S):
memo = {}
def dfs(i, target):
if target == 0:
return True
if i == len(nums) or target < 0:
return False
if (i, target) in memo:
return memo[(i, target)]
include = dfs(i + 1, target - nums[i])
exclude = dfs(i + 1, target)
memo[(i, target)] = include or exclude
return memo[(i, target)]
return dfs(0, S)
# Driver code
if __name__ == '__main__':
nums = [3, 34, 4, 12, 5, 2]
S = 9
print(subset_sum(nums, S)) # True
Line Notes
memo = {}Initialize cache to store results of subproblems
if (i, target) in memo:Return cached result if available to avoid recomputation
memo[(i, target)] = include or excludeStore result of current subproblem
return memo[(i, target)]Return cached or computed result
import java.util.*;
public class SubsetSum {
static Map<String, Boolean> memo = new HashMap<>();
public static boolean subsetSum(int[] nums, int S) {
memo.clear();
return dfs(nums, 0, S);
}
private static boolean dfs(int[] nums, int i, int target) {
if (target == 0) return true;
if (i == nums.length || target < 0) return false;
String key = i + "," + target;
if (memo.containsKey(key)) return memo.get(key);
boolean include = dfs(nums, i + 1, target - nums[i]);
boolean exclude = dfs(nums, i + 1, target);
memo.put(key, include || exclude);
return memo.get(key);
}
public static void main(String[] args) {
int[] nums = {3, 34, 4, 12, 5, 2};
int S = 9;
System.out.println(subsetSum(nums, S)); // true
}
}
Line Notes
static Map<String, Boolean> memo = new HashMap<>();Cache to store subproblem results
String key = i + "," + target;Create unique key for memoization
if (memo.containsKey(key)) return memo.get(key);Return cached result if present
memo.put(key, include || exclude);Store computed result
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
unordered_map<string, bool> memo;
string makeKey(int i, int target) {
return to_string(i) + "," + to_string(target);
}
bool dfs(const vector<int>& nums, int i, int target) {
if (target == 0) return true;
if (i == nums.size() || target < 0) return false;
string key = makeKey(i, target);
if (memo.find(key) != memo.end()) return memo[key];
bool include = dfs(nums, i + 1, target - nums[i]);
bool exclude = dfs(nums, i + 1, target);
memo[key] = include || exclude;
return memo[key];
}
bool subsetSum(const vector<int>& nums, int S) {
memo.clear();
return dfs(nums, 0, S);
}
int main() {
vector<int> nums = {3, 34, 4, 12, 5, 2};
int S = 9;
cout << (subsetSum(nums, S) ? "true" : "false") << endl; // true
return 0;
}
Line Notes
unordered_map<string, bool> memo;Cache for storing subproblem results
string key = makeKey(i, target);Generate unique key for memo
if (memo.find(key) != memo.end()) return memo[key];Return cached result if found
memo[key] = include || exclude;Store computed result
function subsetSum(nums, S) {
const memo = new Map();
function dfs(i, target) {
if (target === 0) return true;
if (i === nums.length || target < 0) return false;
const key = i + ',' + target;
if (memo.has(key)) return memo.get(key);
const include = dfs(i + 1, target - nums[i]);
const exclude = dfs(i + 1, target);
memo.set(key, include || exclude);
return memo.get(key);
}
return dfs(0, S);
}
// Test
console.log(subsetSum([3, 34, 4, 12, 5, 2], 9)); // true
Line Notes
const memo = new Map();Initialize cache for memoization
const key = i + ',' + target;Create unique key for current state
if (memo.has(key)) return memo.get(key);Return cached result if available
memo.set(key, include || exclude);Store computed result
TimeO(n * S)
SpaceO(n * S) for memo and recursion stack
Each subproblem (i, target) is computed once and cached.
💡 For n=20 and S=1000, this reduces calls from millions to about 20,000.
Interview Verdict: Accepted
Efficient enough for moderate constraints and a common interview solution.