1. 程式人生 > >【LeetCode】 【dp】 迴文系列

【LeetCode】 【dp】 迴文系列

以下幾題:

Leetcode 9. Palindrome Number

給定一個數字,判斷數字是否為迴文數字。

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1:

Input: 121
Output: true

Example 2:

Input: -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.

Example 3:

Input: 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.

1,判斷迴文只需要使用兩個指標一前一後比較數字即可。

    bool isPalindrome(int x) {
        if(x<0 || &x==nullptr)
            return false;
        string x_str = to_string(x);
        int lo = 0;
        int hi = x_str.size()-1;
        while(lo<=hi) {
            if (x_str[lo] != x_str[hi])
                return false;
            lo++;
            hi--;
        }
        return true;
    }

這種方法需要先將int轉成string,最終得分在45%左右。

 

2,如何不用換成字串直接判斷呢?

按照最直接的方法,迴文數的定義就是數字從正序或反序來讀都是一樣的,那就將數字顛倒過來後再判斷是否一樣。

因此可以從個位數開始依次讀,再不斷進位相加,得到顛倒的數字。

首先儲存一個輸入x的備份source_x,然後對x的每一位迴圈,reverse_x = reverse_x*10 + x%10 的方式不斷得到高位的數字。如1221可得到 reverse_x = 0*10 + 1221%10 = 1,x = x/10 = 1221/10 = 122。

    bool isPalindrome(int x) {
        if(x<0 || &x==nullptr)
            return false;
        int source_x = x;
        int reverse_x = 0;
        while(x) {
            reverse_x = reverse_x*10 + x%10;
            x = x/10;
        }
        if (source_x == reverse_x)
            return true;
        return false;
    }

 

LeetCode 5. Longest Palindromic Substring

最長迴文子串。使用DP來做。

定義dp[i][j]表示從i到j的字串是否為迴文串

初始化:每個單獨的字母都是迴文串:dp[i][i] = true

遞推:判斷 dp[i][j] 時,若 dp[i+1][j-1] == true 且 s[i] == s[j] ,即對於abcba,bcb是迴文串且 'a' == 'a',因此 abcba 也是迴文串。

注意幾個地方:

1,可以看到遞推時,i 由 i+1 的狀態推得,因此在迴圈時,i 應該從大往小遞推; 

2,對於兩個字元的,如 'bb',中間字串為空,因此初始化時不僅要初始化每個單個的字元 dp[i][i],也要初始化連續的兩個字元 dp[i][i+1]

    string longestPalindrome(string s) {
        /*
        最長連續迴文串
        使用dp,dp[i][j]表示i起點j終點的迴文串長度
        */
        if (s.length() <= 1)
            return s;

        int n = s.length();
        // 首先初始化
        bool dp[n][n] = {false};
        // 所有單個字母都是迴文的
        for (int i=0; i<n; i++) {
            dp[i][i] = true;
            // 兩個相鄰字母相等則也時迴文的
            if (i<n-1)
                dp[i][i+1] = s[i]==s[i+1];
        }
        
        // 遍歷每種可能
        // i應從大到小遍歷
        for (int i=n-3; i>=0; i--) {      
            for(int j=i+2; j<n; j++) {
                dp[i][j] = s[i]==s[j] && dp[i+1][j-1];  // 若i與j處字元相同 且 [i+1][j-1]是迴文
            }
        }
        
        int longest_length = 0;
        string longest_str = "";
        for (int i=0; i<n; i++) {
            for(int j=i; j<n; j++) {
                if (dp[i][j]==true && j-i+1>longest_length) { // 當前是迴文串時 且 是目前的最長的迴文串
                    longest_str = s.substr(i,j-i+1);
                    longest_length = j-i+1;
                }
            }
        }
        
        return longest_str;
    }