一道關於迴文的筆試題

近日參加了一家國內某知名互聯網公司的在線筆試,有一道算法題比較有意思,拿出來分享一下。算法

題目:

給定一個字符串,能夠隨意刪除字符串裏的任何字符(也能夠不刪除),目標是刪除一些字符後讓剩下的字符可以組成迴文,並返回該輸入字符串所能構成的最長迴文長度。數組

例如,輸入:"eabbfa"。spa

刪除e和f後,構成"abba",所以返回4。code

提示:

先看一個遞歸的方法:blog

int recursive(string& s, int start, int end) {
    if (start == end) {
        return 1;
    }
    if (start > end) {
        return 0;
    }
    if (s[start] == s[end]) {
        return recursive(s, start + 1, end - 1) + 2;
    }
    else {
        return max(recursive(s, start, end - 1), recursive(s, start + 1, end));
    }
}

int longestPalindrom(string s) {
    return recursive(s, 0, s.length() - 1);
}

可是遞歸方法會計算許多重複子問題,致使效率降低。遞歸

這題能夠用動態規劃來作。申請一個二維數組,dp[i][j],表明了字符串從 i 到 j 位置的子串中可以包含的最長迴文長度。字符串

顯然,這裏的起始條件是dp[i][i] = 1,i取值爲[0, s.length() - 1],由於只有一個字符的字符串必定是迴文。string

以後能夠用 k 表明 i 和 j 的距離,從1開始遞增。io

當s[i] == s[j]時,進行狀態轉移,返回dp[i][j] = max(dp[i + 1][j - 1] + 2, max(dp[i + 1][j] + 1, dp[i][j - 1] + 1));class

大體思路就是這樣。

代碼:

int longestPalindrom(string s) {
    int len = s.length();
    if (len <= 1) {
        return len;
    }
    vector<vector<int>> dp(len, vector<int>(len, 0));
    int max_len = 1;
    // single character is palindrom
    for (int i = 0; i < len; ++i) {
        dp[i][i] = 1;
    }
    // k is distance between i and j
    for (int k = 1; k < len; ++k) {
        for (int i = 0; i < len - k; ++i) {
            int j = i + k;
            if (s[i] == s[j]) {
                dp[i][j] = max(dp[i + 1][j - 1] + 2, max(dp[i + 1][j] + 1, dp[i][j - 1] + 1));
            }
            else {
                dp[i][j] = max(dp[i + 1][j - 1], max(dp[i + 1][j], dp[i][j - 1]));
            }
        }
    }
    return dp[0][len-1];
}

int main()
{
    string s = "rdgsaraytbbdrcdfcbsbaaoio";
    int res = longestPalindrom(s);
    return 0;
}

若是有更好的思路或者發現代碼有紕漏,歡迎留言指正。

相關文章
相關標籤/搜索