131. Palindrome Partitioning

Leetcode

https://leetcode.com/problems/valid-palindrome/

題目

Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s.

A palindrome string is a string that reads the same backward as forward.

Example 1:

Input: s = "aab"
Output: [["a","a","b"],["aa","b"]]

Example 2:

Input: s = "a"
Output: [["a"]]

解答

  • 方法一

利用 DFS 去 backtracking 所有的迴文子字串

var partition = function(s) {
    // 判斷是否迴文
    const isPalindrome = (start, end) => {
        while(start<end) {
            if(s[start++] !== s[end--]) return false;
        }
        return true;
    }
    
    // 回傳結果
    const res = [];
    // 暫存所有為迴文的子字串
    const temp = [];
    
    const dfs = (start) => {
        // 遍歷過一輪後可以把所有迴文子字串加入到結果矩陣
        if(start>=s.length) {
            // 因為後面有 temp.pop(),會將 res 裡的 temp 也清空,所以這裡要複製一份 temp
            res.push([...temp]);
        }
        let end = start;
        // console.log(start, temp)

        while(end < s.length) {
            if(isPalindrome(start, end)) {
                temp.push(s.substring(start, end+1));
                // 在剩餘字串中繼續尋找迴文子字串
                dfs(end+1)
                // 回到上一輪的 temp 矩陣,end++,繼續尋找迴文子字串
                temp.pop();
            }
            end++;
        }
    }
    dfs(0);
    return res;
};

Runtime: 244 ms, faster than 87.80% of JavaScript online submissions for Palindrome Partitioning.

Memory Usage: 62.2 MB, less than 74.63% of JavaScript online submissions for Palindrome Partitioning.

For example:

s = "aabb"

第一輪從前往後遍歷結束-> temp = ['a', 'a', 'b', 'b'],res = [['a', 'a', 'b', 'b']]

回到上一輪的 temp 矩陣 (temp.pop() 後) -> temp = ['a', 'a', 'b'],start = 3,end = 4

回到上上一輪的 temp 矩陣 (temp.pop() 後) -> temp = ['a', 'a'],start = 2,end = 3

判斷 'bb' 為迴文子字串,將 'bb' 加入 temp -> temp = ['a', 'a', 'bb'],start = 2,end = 3

end+1,繼續 dfs 尋找下一個迴文子字串,如此不斷反覆 backtracking 所有迴文子字串...

  • 方法二

利用 dp 的方式求解,dp[len] 代表從 0 ~ len 可組成的迴文子字串矩陣

var partition = function(s) {
    const isPalindrome = (str) => {
      let start = 0;
      let end = str.length-1;
      while(start<end) {
          if(str[start++] !== str[end--]) return false;
      }
      return true;
    }

    const n = s.length;
    const dp = Array.from(Array(n+1), () => []);
    for(let len=1; len<=n; len++) {
        for(let i=0; i<len; i++) {
            const right = s.substring(i, len);
            if(isPalindrome(right)) {
                // 如果從頭到尾整個字串都是迴文,直接 push 進 dp
                if(i === 0) dp[len].push([right]);
                // 從之前的迴文子字串中尋找,如果 right 是迴文的話
                // 只要把之前迴文子字串的值再加上 right 就是新的迴文子字串了
                for(let arr of dp[i]) {
                    const copyArr = [...arr];
                    copyArr.push(right);
                    dp[len].push(copyArr);
                }
            }
        }
    }
    return dp[n];
};

Runtime: 308 ms, faster than 43.76% of JavaScript online submissions for Palindrome Partitioning.

Memory Usage: 71.1 MB, less than 39.12% of JavaScript online submissions for Palindrome Partitioning.

For example:

s = "babab"

dp[0] = []

dp[1] = [ [b] ]

dp[2] = [ [b, a] ]

dp[3] = [ [b, a, b], [bab] ]

dp[4] = [ [b, a, b, a], [bab, a], [b, aba] ]

dp[5] = [ [b, a, b, a, b], [bab, a, b], [b, aba, b], [b, a, bab], [babab] ]

拿 dp[4] 來觀察,前兩個是由 dp[3] + 判斷最後一個 a 是迴文計算而來,第三個是根據 dp[1] + 判斷 aba 迴文而來

測資

let s = "aab";
// s = "aabb";
// s = "babab";

console.log(partition(s))

參考資料

https://hackmd.io/@Ji0m0/B1dUOaRjN/https%3A%2F%2Fhackmd.io%2F%40Ji0m0%2FS1udpfIo_

https://zxi.mytechroad.com/blog/searching/leetcode-131-palindrome-partitioning/

Last updated

Was this helpful?