Lesson 3 � Intermediate
0/1 Knapsack & Subset Sum
Knapsack DP ka sabse important pattern hai � interview mein har doosre company mein aata hai. 0/1 Knapsack mein har item ya toh lo ya chhodo. Is pattern se Subset Sum, Equal Partition, Count of Subsets sab ban jaate hain. Ek pattern seekho, 5 problems solve karo!
0/1 Knapsack kya hai?
WHAT
Thief ko bag mein items daalne hain. Har item ka weight aur value hai. Bag ki capacity fixed hai. Maximum value le jaao � but har item sirf ek baar le sakte ho (0/1 � ya lo ya mat lo).
WHEN
Jab "ya toh include karo ya exclude karo" wala choice ho, jab items ki limit hai, jab maximum/minimum value find karni ho subject to constraints � tab 0/1 Knapsack lagao.
WHERE
Subset Sum, Equal Partition, Count of Subsets, Target Sum � ye sab 0/1 Knapsack ke variants hain. Knapsack seekh lo, baaki sab easy ho jaayega.
DP Table Visualization
# 0/1 Knapsack: Items = [1,2,3], Weights = [1,2,3], Values = [10,20,30], Capacity = 4
#
# dp[i][w] = i items tak ke saath capacity w ka maximum value
#
# Capacity ? 0 1 2 3 4
# Items ?
# 0 (none) 0 0 0 0 0
# 1 (w=1, v=10) 0 10 10 10 10
# 2 (w=2, v=20) 0 10 20 30 30
# 3 (w=3, v=30) 0 10 20 30 40
#
# Har cell mein decision: item include karo ya mat karo
# Include: val[i-1] + dp[i-1][w - wt[i-1]]
# Exclude: dp[i-1][w]
# Max lo dono mein se
0/1 Knapsack Code
def knapsack(W, wt, val, n):
# dp[i][w] = i items tak capacity w ka max value
dp = [[0] * (W + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for w in range(1, W + 1):
if wt[i - 1] <= w:
# Item include kar sakte hain � max lo include/exclude mein se
include = val[i - 1] + dp[i - 1][w - wt[i - 1]]
exclude = dp[i - 1][w]
dp[i][w] = max(include, exclude)
else:
# Weight zyada hai � sirf exclude
dp[i][w] = dp[i - 1][w]
return dp[n][W]
# Example
val = [60, 100, 120]
wt = [10, 20, 30]
W = 50
n = len(val)
print(f"Maximum value: {knapsack(W, wt, val, n)}") # 220
Subset Sum Problem
Kya array ke kuch elements ka sum target ke barabar ho sakta hai✓ Ye 0/1 Knapsack ka variant hai � weight = element, capacity = target:
# Subset Sum � kya sum = target possible hai?
def subsetSum(arr, target):
n = len(arr)
dp = [[False] * (target + 1) for _ in range(n + 1)]
# 0 elements se sirf 0 sum possible hai
for i in range(n + 1):
dp[i][0] = True
for i in range(1, n + 1):
for s in range(1, target + 1):
if arr[i - 1] <= s:
# Include ya exclude
dp[i][s] = dp[i - 1][s] or dp[i - 1][s - arr[i - 1]]
else:
dp[i][s] = dp[i - 1][s]
return dp[n][target]
# Example
arr = [3, 34, 4, 12, 5, 2]
target = 9
print(f"Sum {target} possible: {subsetSum(arr, target)}") # True (4+5)
Equal Partition Sum
Array ko 2 subsets mein divide karo jinka sum equal ho. Agar total sum even hai toh half sum pe subset sum check karo:
# Equal Partition � array ko 2 equal sum subsets mein todo
def equalPartition(arr):
total = sum(arr)
if total % 2 != 0:
return False # Odd sum � impossible!
return subsetSum(arr, total // 2)
# Example
arr = [1, 5, 11, 5]
print(f"Equal partition possible: {equalPartition(arr)}") # True
# [1,5,5] aur [11] � dono ka sum = 11
Count of Subsets with Given Sum
Kitne subsets hain jinka sum target ke barabar ho? 0/1 se True/False ki jagah count store karo:
# Count Subsets � kitne subsets ka sum = target
def countSubsets(arr, target):
n = len(arr)
dp = [[0] * (target + 1) for _ in range(n + 1)]
for i in range(n + 1):
dp[i][0] = 1 # 0 sum ka 1 subset hai � empty subset
for i in range(1, n + 1):
for s in range(1, target + 1):
if arr[i - 1] <= s:
dp[i][s] = dp[i - 1][s] + dp[i - 1][s - arr[i - 1]]
else:
dp[i][s] = dp[i - 1][s]
return dp[n][target]
# Example
arr = [1, 2, 3, 3]
target = 6
print(f"Subsets with sum {target}: {countSubsets(arr, target)}") # 3
Unbounded Knapsack
Agar same item baar baar le sakte ho toh Unbounded Knapsack lagta hai. Loop order change hota hai � inner loop left-to-right:
# Unbounded Knapsack � same item baar baar le sakte ho
def unboundedKnapsack(W, wt, val, n):
dp = [0] * (W + 1)
for w in range(1, W + 1):
for i in range(n):
if wt[i] <= w:
dp[w] = max(dp[w], val[i] + dp[w - wt[i]])
return dp[W]
# Coin Change bhi unbounded hai � same coin baar baar le sakte ho
def coinChange(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for coin in coins:
if coin <= i and dp[i - coin] != float('inf'):
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
Try it: code khud likho
Exercise
Question: Array = [2, 3, 7, 8, 10] aur target = 11. Kya subset sum possible hai? "True" ya "False" daalo.
Question: Equal Partition Sum problem mein sabse pehle kya check karte hain✓ Sirf ek word daalo.
Common mistakes
- 0/1 vs Unbounded confuse karna: 0/1 mein inner loop W se 1 tak (right-to-left) chalta hai. Unbounded mein left-to-right. Agar same item baar baar le sakte ho toh unbounded hai.
- Base case miss karna: dp[0][w] = 0 for all w (0 items se kuch nahi milega). dp[i][0] = 0 for knapsack, dp[i][0] = True for subset sum. Base case galat hoga toh saari table galat fill hogi.
- Index shift bhool jaana: dp array 1-indexed hota hai (0 se n tak) but original array 0-indexed hai. Isliye
arr[i-1]use karte hain jabdp[i]access karte ho. - Subset Sum mein True/False vs Count confuse karna: Subset Sum = boolean (True/False). Count of Subsets = integer (kitne). Template same hai sirf OR ki jagah + lagta hai.
- Space optimization na karna: Knapsack mein sirf current row aur previous row chahiye � pura 2D table mat banao. 1D array se kaam ho jaata hai.
Knapsack family samajh aa gayi✓ Ab LIS, LCS aur Edit Distance dekhte hain � strings pe DP ka sabse powerful application.