mysql避免回文_关于回文字符串的一些常见问题和解法

问题1 --- 字符串的最长回文子串

思路

回文串是有中心的,选择一个位置作为回文串的中心,然后向两边扩展,便可以找到以该点作为中心的最长回文串,然后选择下一个位置作为中心,重复上述步骤,即可找到最长回文子串。由于回文串的中心不一定是某个字符,比如aa的中心是a#a中的#,因此可以进行字符串的扩展映射,将abcd扩展为#a#b#c#d,当然这并不是真的进行扩展,只是在运算时,将偶数下标当作#,奇数下标/2用来取值,扩展的目的是方便取中心位置。

代码

string longestPalindrome(strings) {int max = 0;intlen;int index = 0;int size =s.size();for(int i = 1; i < 2*size; i++){

len= i%2 + 1;while((i+len) < 2*size && (i-len) >= 0)if(s[(i+len)/2] == s[(i-len)/2])

len+= 2;else

break;

len--;if(max

max=len;

index=i;

}if((max+1)/2 >= (size - i/2))break;

}return s.substr(index/2-max/2,max);

}

问题2 -- 回文子串个数

思路

同样使用问题1的中心扩展思想,扩展一次则个数加1

代码

int countSubstrings(strings) {int len =s.size();int res = 0;intr;for(int i = 1; i < 2*len; i++){if(i%2) res++;

r= 1;while(!((i+r)%2) || (i-r >= 0 && i+r < 2*len+1 && s[(i+r)/2] == s[(i-r)/2])) {if((i+r)%2) res++;;

r++;

}

}returnres;

}

问题3 -- 分割回文串

对于一个字符串s,将其分割为回文串,返回可能的分割方案。例:s = "aba",则返回[  ["a","b","a"], ["aba"] ]; s = "aab",返回 [ ["a","a","b"], ["aa", "b"] ]。

思路

显然,本题可以通过深度优先搜索求解,搜索左边第一个可以被分割的位置,然后搜索剩余未被分割的部分即可。问题在于如何判断是否可以从某个位置分割,这要求我们验证该段是否是回文串,是才能分割该位置,因此,需要首先用动态规划将任意字串是否为回文串保存在dp[len][len]数组中,这样在DFS时直接拿出来用就好了。

此外,在进行深搜时,会出现重复搜索的情况,若想避免重复的递归调用,需要耗费内存去保存被搜索过的状态的分割方案,这样下次搜索到该状态时,不需要递归下去,直接返回分割方案即可,然而在本题中,为了避免重复搜索而使用额外内存记录状态,并不一定能优化算法,实际上,不避免重复搜索的方法效率更高,可能是记录并返回状态信息耗费了大量时间。

代码1 : 不考虑重复搜索

vector>res;

vector> partition(strings) {int len =s.size();if(!len) returnres;

vector> pt(len, vector(len, false));

pt[0][0] = true;for(int i = 1; i < len; i++){

pt[i][i]= true;if(s[i] == s[i-1]) pt[i-1][i] = true;

}for(int i = 2; i < len; i++)for(int j = 0; j < len-i; j++)

pt[j][j+i] = s[j] == s[j+i] && pt[j+1][j+i-1];

vectorans;

dfs(s, ans,0, pt);returnres;

}void dfs(string& s, vector& ans, int k, vector>&pt){if(k ==s.size()) {

res.push_back(ans);return;

}for(int i = k; i < s.size(); i++){if(pt[k][i]) {

ans.push_back(s.substr(k, i-k+1));

dfs(s, ans, i+1, pt);

ans.pop_back();

}

}

}

运行结果:

c82855b7ff4ddc19add5ea2cbb370113.png

代码2:记录搜索状态,避免重复搜索

map>>res;

vector> partition(strings) {int len =s.size();

vector> pt(len, vector(len, false));

pt[0][0] = true;for(int i = 1; i < len; i++){

pt[i][i]= true;if(s[i] == s[i-1]) pt[i-1][i] = true;

}for(int i = 2; i < len; i++)for(int j = 0; j < len-i; j++)

pt[j][j+i] = s[j] == s[j+i] && pt[j+1][j+i-1];return dfs(s, 0, pt);

}

vector> dfs(string& s, int k, vector>&pt){if(res.count(k))returnres[k];

vector>ans;if(k==s.size()) {

vectort;

ans.push_back(t);

res[k]=ans;returnans;

}for(int i = k; i < s.size(); i++){if(pt[k][i]) {for(auto sp:dfs(s,i+1,pt)){

vectorsplit;

split.push_back(s.substr(k, i-k+1));

split.insert(split.end(), sp.begin(), sp.end());

ans.push_back(split);

}

}

}

res[k]=ans;returnans;

}

结果如图:

8a39e8f94748201b44b39d9de1c0e9be.png

问题4 -- 分割回文串2

将一个字符串进行分割,得到的子串都是回文串,求满足要求的最少分割次数。

思路

两次动态规划结合,首先动态规划求出不同子串是否为回文串(同上题),保存在Dp[i][j]中,然后用动态规划求出前k个字符的最少分割次数,状态方程为:

dp[k] = min(dp[i]) + 1,  0<= i < k  && Dp[i+1][k] == true

代码

int minCut(strings) {int len =s.size();if(len < 2) return 0;boolpt[len][len];int pt2[len] = {0};

pt[0][0] = true;for(int i = 1; i < len; i++){

pt[i][i]= true;

pt[i-1][i] = s[i-1] ==s[i];

}for(int i = 2; i < len; i++)for(int j = 0; j < len - i; j++)

pt[j][j+i] = s[j] == s[j+i] && pt[j+1][j+i-1];for(int i = 1; i < len; i++){if(pt[0][i]) {

pt2[i]= 0;continue;

}int j =i;int m = pt2[j-1];while(--j > 0){if(!pt[j][i])continue;

m= min(pt2[j-1], m);

}

pt2[i]= m + 1;

}return pt2[len-1];

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值