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!

? 35 min✓ Intermediate✓ DP Patterns

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)
Subset Sum = 0/1 Knapsack: Agar tumhe sirf "possible hai ya nahi" chahiye toh Subset Sum lagao (boolean DP). Agar maximum value chahiye toh Knapsack lagao (integer DP). Dono ka template same hai � sirf value type alag hai.

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

Lesson complete?

Knapsack family samajh aa gayi✓ Ab LIS, LCS aur Edit Distance dekhte hain � strings pe DP ka sabse powerful application.