2014-05-02 08:29
原题:
Write a function for retrieving the total number of substring palindromes. For example the input is 'abba' then the possible palindromes= a, b, b, a, bb, abba So the result is 6. Updated at 11/11/2013: After the interview I got know that the O(n^3) solution is not enough to go to the next round. It would have been better to know before starting implementing the solution unnecessarily ...
题目:给定一个字符串,统计所有回文子串的个数。O(n^3)的算法是明显的暴力算法,当然要被淘汰了。
解法1:一个简单的优化,是O(n^2)的。从每个位置向两边计算有多少个回文串。这样可以用O(1)空间,O(n^2)时间完成算法。
代码:
1 // http://www.careercup.com/question?id=5177378863054848 2 #include <iostream> 3 #include <string> 4 #include <vector> 5 using namespace std; 6 7 int countPalindrome(const string &s) 8 { 9 int n = (int)s.length(); 10 if (n <= 1) { 11 return n; 12 } 13 14 int i, j; 15 int res; 16 int count; 17 18 res = 0; 19 for (i = 0; i < n; ++i) { 20 j = 0; 21 count = 0; 22 while (i - j >= 0 && i + j <= n - 1 && s[i - j] == s[i + j]) { 23 ++count; 24 ++j; 25 } 26 res += count; 27 28 j = 0; 29 count = 0; 30 while (i - j >= 0 && i + 1 + j <= n - 1 && s[i - j] == s[i + 1 + j]) { 31 ++count; 32 ++j; 33 } 34 res += count; 35 } 36 37 return res; 38 } 39 40 int main() 41 { 42 string s; 43 44 while(cin >> s) { 45 cout << countPalindrome(s) << endl; 46 } 47 48 return 0; 49 }
解法2:有个很巧妙的回文串判定算法,叫Manacher算法,可以在O(n)时间内找出最长回文字串的长度。这题虽然是统计个数,同样可以用Manacher算法搞定。Manacher算法中有个很重要的概念,叫“最长回文匹配半径”,意思是当前最长回文子串能覆盖到的最靠右的位置。每当我们检查的中心位置处于这个半径之内时,就可以和另一边的对称点进行参照,减少一些重复的扫描。如果处于半径之外,就按照常规的方式向两边扫描了。Manacher算法的思想一两句话很难说清楚,在此提供一个链接吧:Manacher算法处理字符串回文。
代码:
1 // http://www.careercup.com/question?id=5177378863054848 2 // Modified Manacher Algorithm 3 #include <algorithm> 4 #include <ctime> 5 #include <iostream> 6 #include <string> 7 #include <vector> 8 using namespace std; 9 10 class Solution { 11 public: 12 long long int countPalindrome(const string &s) { 13 int n = (int)s.length(); 14 15 if (n <= 1) { 16 return n; 17 } 18 19 preProcess(s); 20 n = (int)ss.length(); 21 int far; 22 int far_i; 23 24 int i; 25 26 far = 0; 27 c[0] = 0; 28 for (i = 1; i < n; ++i) { 29 c[i] = 1; 30 if (far > i) { 31 c[i] = c[2 * far_i - i]; 32 if (far - i < c[i]) { 33 c[i] = far - i; 34 } 35 } 36 37 while (ss[i - c[i]] == ss[i + c[i]]) { 38 ++c[i]; 39 } 40 41 if (i + c[i] > far) { 42 far = i + c[i]; 43 far_i = i; 44 } 45 } 46 47 long long int count = 0; 48 for (i = 0; i < n; ++i) { 49 count += (c[i] + (i & 1)) / 2; 50 } 51 52 ss.clear(); 53 c.clear(); 54 55 return count; 56 } 57 private: 58 string ss; 59 vector<int> c; 60 61 void preProcess(const string &s) { 62 int n; 63 int i; 64 65 n = (int)s.length(); 66 ss.clear(); 67 // don't insert '#' here, index may go out of bound. 68 ss.push_back('$'); 69 for (i = 0; i < n; ++i) { 70 ss.push_back(s[i]); 71 ss.push_back('#'); 72 } 73 c.resize(ss.length()); 74 }; 75 }; 76 77 int main() 78 { 79 string s; 80 Solution sol; 81 const int big_n = 500000; 82 83 s.resize(big_n); 84 for(int i = 0; i < big_n; ++i) { 85 s[i] = 'a'; 86 } 87 88 clock_t start, end; 89 start = clock(); 90 cout << sol.countPalindrome(s) << endl; 91 end = clock(); 92 cout << "Runtime for test case of size " << big_n << ": " 93 << (1.0 * (end - start) / CLOCKS_PER_SEC) 94 << " seconds." << endl; 95 96 while (cin >> s) { 97 cout << sol.countPalindrome(s) << endl; 98 } 99 100 return 0; 101 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)