101 Logo
onenoughtone

State Compression Pattern

What is State Compression?

State Compression is a technique used to optimize the space complexity of dynamic programming solutions by reducing the dimensionality of the state space or storing only the necessary states.

It's particularly useful when the solution only depends on a small subset of the previously computed states.

When to Use State Compression

State Compression is useful when:

  • The current state only depends on a few previous states
  • You need to optimize the space complexity of your solution
  • You're dealing with large input sizes that would cause memory issues
  • You're working with multi-dimensional DP problems that can be reduced to fewer dimensions

Common State Compression Techniques

  1. Rolling Array: Use a small number of arrays to represent the current and previous states
  2. Dimension Reduction: Reduce the dimensionality of the DP table (e.g., 2D to 1D)
  3. State Encoding: Encode multiple states into a single value (e.g., using bit manipulation)
  4. Sliding Window: Keep only a window of the most recent states

Example: Optimized Fibonacci

Here's a space-optimized solution for computing the nth Fibonacci number:

function fibonacci(n) { // Handle base cases if (n <= 1) return n; // Initialize variables for the previous two Fibonacci numbers let prev2 = 0; // F(0) let prev1 = 1; // F(1) let current; // Compute Fibonacci numbers iteratively for (let i = 2; i <= n; i++) { // F(i) = F(i-1) + F(i-2) current = prev1 + prev2; // Update variables for the next iteration prev2 = prev1; prev1 = current; } // Return the nth Fibonacci number return prev1; } // Example usage: console.log(fibonacci(10)); // Output: 55 console.log(fibonacci(40)); // Output: 102334155

Example: Optimized Knapsack

Here's a space-optimized solution for the 0/1 knapsack problem:

function knapsack(weights, values, capacity) { const n = weights.length; // Create a 1D array instead of 2D // dp[w] represents the maximum value that can be obtained // with a knapsack capacity of w const dp = Array(capacity + 1).fill(0); // Fill the array in a bottom-up manner for (let i = 0; i < n; i++) { // Important: iterate from right to left to avoid using the same item multiple times for (let w = capacity; w >= weights[i]; w--) { dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]); } } // Return the maximum value return dp[capacity]; } // Example usage: const weights = [2, 3, 4, 5]; const values = [3, 4, 5, 6]; const capacity = 8; console.log(knapsack(weights, values, capacity)); // Output: 10 (items with values 4 and 6)

Example: Optimized LCS

Here's a space-optimized solution for finding the longest common subsequence:

function longestCommonSubsequence(text1, text2) { const m = text1.length; const n = text2.length; // Ensure text1 is the shorter string to minimize space if (m > n) { return longestCommonSubsequence(text2, text1); } // Create two 1D arrays instead of a 2D array let prev = Array(m + 1).fill(0); let curr = Array(m + 1).fill(0); // Fill the arrays in a bottom-up manner for (let j = 1; j <= n; j++) { for (let i = 1; i <= m; i++) { if (text1[i - 1] === text2[j - 1]) { curr[i] = prev[i - 1] + 1; } else { curr[i] = Math.max(prev[i], curr[i - 1]); } } // Swap arrays for the next iteration [prev, curr] = [curr, prev]; } // Return the length of LCS (result is in prev after the last swap) return prev[m]; } // Example usage: console.log(longestCommonSubsequence("abcde", "ace")); // Output: 3 (LCS is "ace") console.log(longestCommonSubsequence("abc", "abc")); // Output: 3 (LCS is "abc") console.log(longestCommonSubsequence("abc", "def")); // Output: 0 (no common subsequence)

Pros and Cons of State Compression

Pros:

  • Significantly reduces space complexity
  • Enables solving problems with larger input sizes
  • Can improve cache performance due to better memory locality

Cons:

  • Often makes the code more complex and harder to understand
  • May make it difficult to reconstruct the solution (e.g., the actual items in the knapsack)
  • Requires careful analysis of state dependencies
IntroVisualizePatternsPractice
101 Logo
onenoughtone