Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources
Palindrome Partitioning II

Palindrome Partitioning II

Problem Statement

Imagine you’re a word sculptor with a string and a mission: slice it into the fewest possible pieces, each a perfect palindrome. This hard-level DP challenge is all about symmetry—how few cuts can you make to turn chaos into mirrored masterpieces? Given a string, return the minimum number of cuts needed.

Example

Input: s = "aab"

Output: 1 (Cut into "aa" | "b")

Input: s = "a"

Output: 0 (Already a palindrome)

Input: s = "abracadabra"

Output: 4 (e.g., "a" | "b" | "r" | "aca" | "dabra" needs at least 4 cuts)

Code

Java
Python
JavaScript
public class Solution {
    public int minCut(String s) {
        int n = s.length();
        int[] dp = new int[n + 1];
        boolean[][] isPal = new boolean[n][n];
        for (int i = 0; i <= n; i++) dp[i] = i - 1; // Max cuts possible
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                if (s.charAt(j) == s.charAt(i) && (i - j <= 2 || isPal[j + 1][i - 1])) {
                    isPal[j][i] = true;
                    dp[i + 1] = Math.min(dp[i + 1], j == 0 ? 0 : dp[j] + 1);
                }
            }
        }
        return dp[n];
    }
}
            
def min_cut(s):
    n = len(s)
    dp = list(range(n + 1))  # dp[i] = min cuts for s[0:i]
    is_pal = [[False] * n for _ in range(n)]
    for i in range(n):
        min_cuts = i  # Worst case: cut at every char
        for j in range(i + 1):
            if s[j] == s[i] and (i - j <= 2 or is_pal[j + 1][i - 1]):
                is_pal[j][i] = True
                min_cuts = min(min_cuts, 0 if j == 0 else dp[j] + 1)
        dp[i + 1] = min_cuts
    return dp[n]
            
function minCut(s) {
    let n = s.length;
    let dp = Array(n + 1).fill().map((_, i) => i - 1); // Max cuts
    let isPal = Array(n).fill().map(() => Array(n).fill(false));
    for (let i = 0; i < n; i++) {
        let minCuts = i;
        for (let j = 0; j <= i; j++) {
            if (s[j] === s[i] && (i - j <= 2 || isPal[j + 1][i - 1])) {
                isPal[j][i] = true;
                minCuts = Math.min(minCuts, j === 0 ? 0 : dp[j] + 1);
            }
        }
        dp[i + 1] = minCuts;
    }
    return dp[n];
}
            

Explanation

  • DP Insight: dp[i] represents the minimum cuts needed for the substring s[0:i].
  • Palindrome Check: Use a 2D table to mark palindromic substrings efficiently.
  • Flow: For each position i, check all possible palindromic prefixes ending at i and minimize cuts based on prior results.
  • Example Walkthrough: "aab" → dp[0]=-1, dp[1]=0 ("a"), dp[2]=0 ("aa"), dp[3]=1 ("aa"|"b").
  • Optimization: Combines palindrome detection with DP to avoid redundant checks.

Note

Time complexity: O(n²), Space complexity: O(n²). Slice through the string with surgical precision—a DP masterpiece!