【题目】
将一个非常长的字符串,切割成一段一段的子字符串,子字符串都是回文字符串。有回文字符串就输出最长的。没有回文就输出一个一个的字符。
比如:habbafgh
输出h,abba,f,g,h。
【思路一】
基于“最长回文子串算法”求出当前字符串的最长回文子串,就能够分成3部分
a、最长回文子串left部分
b、最长回文子串
c、最长回文子串right部分
然后分别求a和c的最长回文子串
递归至每部分都成单个字符+当前最长回文子串,就能够分解成终于结果。
【代码一】
#include<string> #include<iostream> using namespace std; // beg end 用于返回最大回文串的范围 void MaxPalindromeNumber(string str,int& beg,int& end){ int maxLen = 1,start = beg; int left,right; for(int i = beg;i <= end;i++){ //奇数字串 int oddLen = 1; left = i-1; right = i+1; while(left >= beg && right <= end && str[left] == str[right]){ left--; right++; oddLen += 2; } //更新最大长度 if(oddLen > maxLen){ maxLen = oddLen; //记录当前最大回文串的起始位置 start = left+1; } //偶数字串 left = i; right = i+1; int evenLen = 0; while(left >= beg && right <= end && str[left] == str[right]){ left--; right++; evenLen += 2; } //更新最大长度 if(evenLen > maxLen){ maxLen = evenLen; //记录当前最大回文串的起始位置 start = left+1; } } beg = start; end = start + maxLen - 1; } int index = 0; void SpilitPalindromeNumber(string str,int& beg,int& end){ int lbeg = beg; int rend = end; //beg end 返回当前最大回文串的起始点和截止点 MaxPalindromeNumber(str,beg,end); int lend = beg - 1; int rbeg = end + 1; // lbeg lend 最大回文串的左部 // rbeg rend 最大回文串的右部 if(lbeg <= lend){ SpilitPalindromeNumber(str,lbeg,lend); } //控制格式输出 if(index == 0){ cout<<str.substr(beg,end-beg+1); index++; } else{ cout<<","<<str.substr(beg,end-beg+1); index++; } if(rbeg <= rend){ SpilitPalindromeNumber(str,rbeg,rend); } } int main(){ string str="djdslkAABCDEAfjdl1234321skjflkdsjfkldsababasdlkfjsdwieowowwpw"; int beg = 0; int end = str.length()-1; SpilitPalindromeNumber(str,beg,end); return 0; }
【思路二】
先将给定字符串翻转,然后和原来的字符串一起。这样就变成了最长公共子序列问题。
此时能够利用动态规划的思路来完毕。
关于最长公共子序列问题能够參考<算法导论>里面有具体的说明
相关链接: