- 题目一:最长连续回文子串。
- 问题分析:回文串顾名思义表示前后读起来都是一样,这里面又是需要连续的。分析这个问题的结构,可以想到多种方法。暴力解决的方式,2层循环遍历得出各个子串,然后再去判断该子串是否回文,这样的话O(N)=n的三次方,还有一种是dp解决。
- 解题方法一:暴力解决的方法。前面已经讲到了方法,下面给出方法的实现。
class Solution {
public:
string longestPalindrome(string s) {
int maxlength = ;
int start = , end = ;
for (int i=; i<s.size(); i++){
for (int j=i+; j<s.size(); j++){
int temp1, temp2;
for (temp1=i, temp2=j; temp1<temp2; temp1++, temp2--){
if (s[temp1] != s[temp2])
break;
}
if (temp1>=temp2 && j-i>maxlength){
maxlength = j-i+;
start = i;
end = j;
}
}
}
if (maxlength > )
s.substr(start, maxlength);
return NULL;
} }; - 解题方法二:DP求解。为什么会想到dp求解呢。首先分析问题。最长连续子串是否回文。如果一个子串回文,那么子串的子串也就是回文的,依次类推就简化为一个小的解,从而得到整体的解。
具体思路:设置一个int二维数组DP[i][j]用来存储从i到j的串是否回文,1表示是,0表示否。
这里有三种情况需要考虑:①:当只有一个字符的时候,i=j,肯定回文 DP[i][j] = 1;
②:当两个两个字符相邻的时候,如果他们相等,那么他们也是回文的,i-j<2 && s[i]==s[j] -> DP[i][j] = 1
③:当超过两个字符的时候,如果他们首尾是相同的并且除去首尾字符的剩余字符也是回文的话,那么这个串也是回文的。
s[i] == s[j] && DP[i+1][j-1] = 1 ->DP[i][j] = 1
考虑完这三种情况,就设置两个指针记录最长回文子串的左右位置,然后直接提取出来即可。DP[i][j] = 1 并且最长字符长度小于当前字符长度。 class Solution {
public:
string longestPalindrome(string s) {
int dp[s.size()][s.size()] ;
int left = , right = , maxlength = ;
for (int i=; i<s.size(); i++){
for (int j=; j<i; j++){
//这里表示出了所有的情况
//当为相邻两个字符串时,如果相等则为1,当大于两个字符串时,如果首尾相同并且子串是回文的话,那么这个串也是回文
dp[j][i] = (s[i] == s[j] && ((i-j < ) || dp[j+][i-]));
if (dp[j][i] && maxlength< i-j+) {
maxlength = j-i+;
left = j;
right = i;
}
}
dp[i][i] = ;//这里表示单个字符串就是回文串。
}
return s.substr(left, right-left+);
}
};
- 题目二:给出一个整数,判断这个整数是否是回文数字,不能使用额外的存储空间,意思是不能将他变为字符串。
- 题目分析:第一想到的就是将他变成一个字符串然后对他进行判断是否是回文串。但是题目不能变为字符串。这里我们就可以变换一种方法。比如对数字“12321”,12321/10000=1,首位为1, 12321%10=1,尾部为1,然后继续判断232这个数字,按照相同的方法(这里的关键是剩余数字的位数需要确定)
- 代码:
class Solution {
public:
bool isPalindrome(int x) {
if (x < )
return false;
int flag = ;
while(x/flag >= ){//求整数的最高位 -》这是求最高位的位数的技巧
flag *= ;
}
while (x) {
int left = -, right = -;
left = x/flag;
right = x%;
if (left != right)
return false;
x = (x%flag)/;
flag = flag/;
}
return true;
}
};
- 题目三:判断一个字符串是否是回文,只考虑字母和数字,其他空格之类的忽略。
- 思路:这个就是简答的判断字符串是否是回文的情况。碰到不是字母或者是数字的情况直接跳转到下一个字符串,头尾依次进行比较。这里需要考虑大小写的问题,所以比较是否相同直接利用assic的值进行比较比较合适。s[left] +32 -'a')%32 != (s[right] +32 -'a')%32 ->>这里%32表示大小写的assic 32是一个循环。
- 代码
class Solution {
public:
bool isPalindrome(string s) {
int len = s.size();
int left = , right = len-;
while (left < right){
if (!isAlphaNum(s[left]))
left++;
else if (!isAlphaNum(s[right]))
right--;
else if((s[left] + -'a')% != (s[right] + -'a')%)
return false;//这里考虑到大小写,所以直接这样用assic进行比较
else{
left++,right--;
}
}
return true;
}
bool isAlphaNum(char &ch) {
if (ch >= 'a' && ch <= 'z') return true;
if (ch >= 'A' && ch <= 'Z') return true;
if (ch >= '' && ch <= '') return true;
return false;
}
};
- 题目四:
给定一个字符串s,分区s使得分区的每个子字符串是一个回文。 返回s的所有可能的回文分区。 例如,给定s =“aab”,
返回 [
[“aa”,“b”],
[“a”,“a”,“b”]
]]- 题目分析:实际上这道题目是一道组合的题目,对付组合的题目,回溯法是一个很好的方法。这里是要拆分字符串(拆分的串都是回文串),得出所有的拆分情况。组合问题->回溯法,DFS算法很好的解决了这个问题。先是针对一个一个字符进行拆分,然后是针对两个字符是回文串的串,之后是含有三个字符是回文串的字符,依次类推(这里需要一个函数是判断该字符串是否为回文的函数,给定首尾进行判断)。dfs递归的条件是找到符合要求的回文串,然后对后面的串也进行递归的求解(从头开始继续进行递归求解)
- 实例分析:
a b c e e -> 第一组:a 回文 a进temp, b回文 b进temp, c 回文 c进temp , e 回文 e进temp , e 回文 e进temp找到一组,出容器。
第二组:回溯,回溯到第一个e,进行两个字符回文查找判断,找到ee,之后就没有了。 - 代码:
class Solution {
public:
vector<vector<string>> partition(string s) {
vector<vector<string> > res;
vector<string> temp;
partition(s, , temp, res);
return res;
}
void partition(string &s, int start, vector<string> temp, vector<vector<string> > &res){
int len = s.size();
if (start == len)
res.push_back(temp);
for (int i=start; i<len; i++){
if (isPalindromeStr(s, start, i)){
temp.push_back(s.substr(start, i-start+));
partition(s, i+, temp, res);
temp.pop_back();
}
}
}
bool isPalindromeStr(string s, int start, int end){
while (start < end){
if (s[start] != s[end]){
return false;
}else
start++,end--;
}
return true;
}
};