Bitmask DP for Subset Problems
Bitmask DP uses bit manipulation to represent subsets as integers. Each bit indicates whether an element is included.
Bitmask Basics
// Represent subset using integer bitmask
int mask = 0;
mask |= (1 << i); // Add element i to subset
mask &= ~(1 << i); // Remove element i from subset
mask ^= (1 << i); // Toggle element i in subset
boolean has = (mask & (1 << i)) != 0; // Check if element i is in subset
// Iterate through all subsets
for (int mask = 0; mask < (1 << n); mask++) {
// mask represents a subset
}
Traveling Salesman Problem (TSP)
Find shortest route visiting all cities exactly once and returning to start.
// dp[mask][i] = min cost to visit cities in mask, ending at city i
public int tsp(int[][] dist) {
int n = dist.length;
int[][] dp = new int[1 << n][n];
// Initialize with infinity
for (int[] row : dp) Arrays.fill(row, Integer.MAX_VALUE);
// Base case: start at city 0
dp[1][0] = 0; // mask = 1 (only city 0), at city 0, cost = 0
for (int mask = 1; mask < (1 << n); mask++) {
for (int u = 0; u < n; u++) {
if (dp[mask][u] == Integer.MAX_VALUE) continue;
if ((mask & (1 << u)) == 0) continue; // u must be in mask
// Try visiting unvisited city v
for (int v = 0; v < n; v++) {
if ((mask & (1 << v)) != 0) continue; // v not visited
int newMask = mask | (1 << v);
dp[newMask][v] = Math.min(dp[newMask][v], dp[mask][u] + dist[u][v]);
}
}
}
// Return to start
int fullMask = (1 << n) - 1;
int result = Integer.MAX_VALUE;
for (int u = 0; u < n; u++) {
result = Math.min(result, dp[fullMask][u] + dist[u][0]);
}
return result;
}
TSP Trace Example
Cities: 4, dist matrix given
States: 2^4 = 16 masks
mask=0001 (city 0 visited): dp[1][0] = 0
mask=0011 (cities 0,1): dp[3][1] = dist[0][1]
mask=0111 (cities 0,1,2): dp[7][2] = min(dp[3][1]+dist[1][2], ...)
mask=1111 (all cities): dp[15][3] = min cost to visit all, end at 3
Answer: min over u of dp[15][u] + dist[u][0]
Assignment Problem
Assign n tasks to n workers with minimum cost.
// dp[mask] = min cost to assign tasks in mask
public int minAssignmentCost(int[][] cost) {
int n = cost.length;
int[] dp = new int[1 << n];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int mask = 0; mask < (1 << n); mask++) {
int taskCount = Integer.bitCount(mask);
if (taskCount >= n) continue;
for (int task = 0; task < n; task++) {
if ((mask & (1 << task)) != 0) continue; // Task already assigned
int newMask = mask | (1 << task);
dp[newMask] = Math.min(dp[newMask], dp[mask] + cost[taskCount][task]);
}
}
return dp[(1 << n) - 1];
}
Complexity
- Time: O(2^n * n^2) for TSP
- Space: O(2^n * n) for TSP
- Works for n <= 20 (2^20 ≈ 1M states)
Multi-State DP Problems
Some problems require tracking multiple state variables simultaneously.
House Robber II (Circular)
Houses are arranged in a circle. Adjacent houses cannot both be robbed.
// Break circle by considering two cases:
// Case 1: Include house 0, exclude house n-1
// Case 2: Exclude house 0, include house n-1
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) return 0;
if (n == 1) return nums[0];
return Math.max(robRange(nums, 0, n - 2),
robRange(nums, 1, n - 1));
}
private int robRange(int[] nums, int start, int end) {
int prev2 = 0, prev1 = 0;
for (int i = start; i <= end; i++) {
int curr = Math.max(prev1, prev2 + nums[i]);
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
Best Time to Buy and Sell Stock with Cooldown
// State machine DP: hold, sold, cooldown
public int maxProfit(int[] prices) {
int n = prices.length;
if (n <= 1) return 0;
int hold = -prices[0]; // Maximum profit holding a stock
int sold = 0; // Maximum profit just sold
int cooldown = 0; // Maximum profit in cooldown
for (int i = 1; i < n; i++) {
int prevHold = hold;
int prevSold = sold;
int prevCooldown = cooldown;
hold = Math.max(prevHold, prevCooldown - prices[i]);
sold = prevHold + prices[i];
cooldown = Math.max(prevCooldown, prevSold);
}
return Math.max(sold, cooldown);
}
Paint House II (K Colors)
// Paint n houses with k colors, adjacent houses different colors
// Find minimum cost
public int minCostII(int[][] costs) {
int n = costs.length, k = costs[0].length;
int prevMin1 = 0, prevMin2 = 0; // Two smallest costs
int prevColor1 = -1; // Color with minimum cost
for (int i = 0; i < n; i++) {
int currMin1 = Integer.MAX_VALUE, currMin2 = Integer.MAX_VALUE;
int currColor1 = -1;
for (int j = 0; j < k; j++) {
int cost = costs[i][j] + (j == prevColor1 ? prevMin2 : prevMin1);
if (cost < currMin1) {
currMin2 = currMin1;
currMin1 = cost;
currColor1 = j;
} else if (cost < currMin2) {
currMin2 = cost;
}
}
prevMin1 = currMin1;
prevMin2 = currMin2;
prevColor1 = currColor1;
}
return prevMin1;
}
State Machine DP Pattern
// Model problem as state machine with transitions
// States: S1, S2, ..., Sk
// At each step, you can transition between states
// dp[i][state] = max/min value at step i in state
// Generic template:
int[][] dp = new int[n + 1][numStates];
for (int i = 1; i <= n; i++) {
for (int state = 0; state < numStates; state++) {
for (int prevState : validPrevStates(state)) {
dp[i][state] = optimize(dp[i][state], dp[i-1][prevState] + transition(state));
}
}
}
return optimize over final states of dp[n][state];
When to Use Multi-State DP
- Problem has multiple "modes" or "phases"
- Decisions depend on previous state (not just position)
- Need to track multiple attributes simultaneously
- State transitions form a graph/machine
Practice Problems
Given n cities and distances between them, find the shortest possible route that visits each city exactly once and returns to the starting city. This is the classic TSP problem.
Example:
Input: dist = [[0,10,15,20],[10,0,35,25],[15,35,0,30],[20,25,30,0]]
Output: 80
Optimal route: 0→1→3→2→0 with total distance 10+25+30+15=80.
Optimal Solution — O(2^n * n^2) time, O(2^n * n) space
Bitmask DP. dp[mask][i] = minimum cost to visit all cities in mask, ending at city i. For each state, try extending to unvisited cities.
class Solution {
public int tsp(int[][] dist) {
int n = dist.length;
int[][] dp = new int[1 << n][n];
for (int[] row : dp) Arrays.fill(row, Integer.MAX_VALUE);
dp[1][0] = 0; // Start at city 0
for (int mask = 1; mask < (1 << n); mask++) {
for (int u = 0; u < n; u++) {
if (dp[mask][u] == Integer.MAX_VALUE) continue;
if ((mask & (1 << u)) == 0) continue;
for (int v = 0; v < n; v++) {
if ((mask & (1 << v)) != 0) continue;
int newMask = mask | (1 << v);
dp[newMask][v] = Math.min(dp[newMask][v],
dp[mask][u] + dist[u][v]);
}
}
}
int fullMask = (1 << n) - 1;
int result = Integer.MAX_VALUE;
for (int u = 0; u < n; u++) {
result = Math.min(result, dp[fullMask][u] + dist[u][0]);
}
return result;
}
}Edge Cases:
- Single city: return 0
- Two cities: return dist[0][1] * 2
- Complete graph vs sparse graph
- All distances equal
Quiz
1. In bitmask DP, what does mask = 1011 (binary) represent?
2. What is the time complexity of TSP using bitmask DP?
3. What is the primary purpose of State Compression & Multi-State DP?
4. What is a common mistake when implementing State Compression & Multi-State DP?
Flashcards
Question
What does dp[mask][i] represent in TSP?
Click to reveal answer
Answer
The minimum cost to visit all cities in the subset represented by mask, ending at city i.
Question
How do you check if city i is in subset mask?
Click to reveal answer
Answer
Use bitmask: (mask & (1 << i)) != 0. If true, city i is included in the subset.
Question
What is State Compression & Multi-State DP?
Click to reveal answer
Answer
State Compression & Multi-State DP is a key concept in software engineering.
Question
When to use State Compression & Multi-State DP?
Click to reveal answer
Answer
Use State Compression & Multi-State DP when building production systems that require reliability, scalability, and maintainability.
Question
State Compression & Multi-State DP best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Bitmask DP: use integer bits to represent subsets
- 2.dp[mask][i] tracks optimal value for subset mask ending at i
- 3.TSP: O(2^n * n^2) with bitmask DP
- 4.State machine DP models problems as state transitions
Interview Tips
- •Start with brute force to understand the problem
- •Explain bitmask representation clearly
- •For TSP, trace through small examples
- •Discuss space optimization if time allows
Cheat Sheet
State DP Cheat Sheet
Bitmask DP:
- Use integer bitmask to represent subset
- mask | (1 << i): add element i
- mask & (1 << i): check element i
- dp[mask][i] = optimal value for subset mask ending at i
TSP:
- dp[mask][i] = min cost to visit cities in mask, end at i
- Base: dp[1][0] = 0 (start at city 0)
- Transition: dp[mask|1<<v][v] = min(dp[mask][u] + dist[u][v])
- Answer: min over u of dp[fullMask][u] + dist[u][0]
State Machine DP:
- Model problem as states with transitions
- dp[i][state] = value at step i in state
- Track multiple attributes (hold/sold/cooldown)
Complexity:
- Bitmask: O(2^n * n^2) time, O(2^n * n) space
- Works for n <= 20
Common Patterns:
- Circular problems: break into two linear cases
- Cooldown/dependency: use state machine
- Subset selection: use bitmask