题目
647. 回文子串
我的思路
设两个指针,遍历两个指针之间形成的字符串?复杂度n*n*n如何优化
第一次遍历设置一个指针,从头到尾扫描。该指针作为可能是回文串的子串的最中间字符。一次判断该指针两侧的字符是否匹配,若匹配则计数并继续判断更外侧的字符
第二次遍历设置两个指针,两个指针始终相邻,也从头到尾扫描字符串。若两个指针指向的字符匹配,那么继续判断两侧的字符是否匹配并计数,直到不匹配或者达到字符串边界
n*n的复杂度
我的实现
class Solution { public: int countSubstrings(string s) { int left,right; int pos1 = 0; int maxPos = s.size()-1; int count = 0; while(pos1<=maxPos){ left = pos1-1; right = pos1+1; count++; while(left>=0&&right<=maxPos){ if(s[left]==s[right]){ count++; left--; right++; }else{ break; } } pos1++; } pos1=0; while(pos1<maxPos){ left = pos1; right = pos1+1; while(left>=0&&right<=maxPos){ if(s[left]==s[right]){ count++; left--; right++; }else{ break; } } pos1++; } return count; } };
拓展学习
马拉车算法可以把时间复杂度降到On
核心思想:
首先可以在源字符串的所有字符之间插入一个特殊字符,这样,偶数或奇数长度的回文子串都对应一个奇数长度的回文串,方便计算。
在对依次每一个字符进行中心拓展时,其实可以利用回文串的特点减少累赘计算。如果当前字符处于此前发现过的回文子串中,那么以当前字符为中心发现回文子串不必从当前字符两侧相邻的字符开始,由于对称性,至少可以从此前已发现的那个包含当前字符的回文串的右边界作为当前字符为中心的字符串的右边界开始匹配。
这样的话,需要借助辅助空间存储已经访问的字符的以它为中心的最大回文串长度。以空间换时间,需要On的空间复杂度,时间复杂度降到了On。
class Solution { public: int countSubstrings(string s) { int n = s.size(); string t = "$#"; for (const char &c: s) { t += c; t += '#'; } n = t.size(); t += '!'; auto f = vector <int> (n); int iMax = 0, rMax = 0, ans = 0; for (int i = 1; i < n; ++i) { // 初始化 f[i] f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1; // 中心拓展 while (t[i + f[i]] == t[i - f[i]]) ++f[i]; // 动态维护 iMax 和 rMax if (i + f[i] - 1 > rMax) { iMax = i; rMax = i + f[i] - 1; } // 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整 ans += (f[i] / 2); } return ans; } }; 作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/palindromic-substrings/solution/hui-wen-zi-chuan-by-leetcode-solution/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。