近日参加了一家国内某知名互联网公司的在线笔试,有一道算法题比较有意思,拿出来分享一下。算法
给定一个字符串,能够随意删除字符串里的任何字符(也能够不删除),目标是删除一些字符后让剩下的字符可以组成回文,并返回该输入字符串所能构成的最长回文长度。数组
例如,输入:"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; }
若是有更好的思路或者发现代码有纰漏,欢迎留言指正。