这两道题都是关于回文串的题目。
之前在语言入门的时候,我们做过 判断一个字符串是否回文,我们知道可以用双指针的方法解法:即左右夹逼,往中间靠拢,找出s[i]!=s[j]则返回false。做了这两道题之后,参考别人的解答,发现除了“左右往中间靠拢”的方法外,还可以使用“中间往两边发散”的方法。
如下面两道题
题目一
解法1 暴力搜索
看到题目很直接的思路,遍历搜索出所有字串,依次判断是否为回文串即可。
双重循环,外层控制字符串起始位置,内层循环遍历字符串终止位置。
class Solution {
public:
int countSubstrings(string s) {
int count = 0;
int n = s.size();
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
{
if(judge(s,i,j))
{
count++;
}
}
return count;
}
bool judge(string &s, int begin, int end)
{
while(begin<end)
{
if(s[begin]!=s[end])
return false;
begin++;
end--;
}
return true;
}
};
时间复杂度为O(n^3),很高。
解法2 中心扩展
以某一个字符为中心,依次向其两边扩展,若s[i]==s[j],说明s(i~j)的是一个回文串。那我们只需要一层循环遍历每一个字符即可。
需要注意的是,每一个扩展,字串长度是+2的。而子串有奇偶之分。当子串为奇数时,中心的左右起点都为该字符本身。当子串为偶数时,中心的右起点为该字符本身位置+1。
class Solution {
public:
int countSubstrings(string s) {
int res=0;
for(int i=0;i<s.size();i++)
{
res+=Center_spread(s,i,i);
res+=Center_spread(s,i,i+1);
}
return res;
}
int Center_spread(string &s, int i, int j)
{
int count=0;
while(i>=0&&j<s.size()&&s[i]==s[j])
{
count++;
i--;
j++;
}
return count;
}
};
题目二
解法1暴力搜索
同样,我们可使用暴力搜索,双重循环找出所有的回文字串,同时维护一个长度最大的字串。
class Solution {
public:
string longestPalindrome(string s) {
int n =s.size();
int max_size = 0;
string res;
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
{
if(judge(s,i,j))
{
if((j-i+1)>=max_size)//j-i+1 为子串长度,这里的比较类似打擂台,不断比较找出最大值
{
res = s.substr(i,j-i+1);
max_size = j-i+1;
}
}
}
return res;
}
bool judge(string&s, int begin, int end)
{
while(begin<end)
{
if(s[begin]!=s[end])
return false;
begin++;
end--;
}
return true;
}
};
解法2中心扩展
同样,我们可使用中心扩展法,一层循环遍历每次为中心点的字符。
中心扩展法在上题中返回的是回文子串的个数。当其跳出while循环时,我们其实可以拿到以当前字符为中心,最长子串左边的位置和右边的位置。
然后我们在for循环中维护一个最长子串左边位置和右边位置即可。
class Solution {
public:
string longestPalindrome(string s) {
int n= s.size();
int max_left =0;
int max_right = 0;
for(int i=0;i<n;i++)
{
auto[left1,right1] = center_spread(s,i,i);
auto[left2,right2] = center_spread(s,i,i+1);
if(right1-left1>max_right-max_left)
{
max_left = left1;
max_right = right1;
}
if(right2-left2>max_right-max_left)
{
max_right = right2;
max_left = left2;
}
}
return s.substr(max_left,max_right-max_left+1);
}
pair<int,int> center_spread(string &s, int i, int j)
{
while(i>=0&&j<s.size()&&s[i]==s[j])
{
i--;
j++;
}
return {i+1,j-1};
}
};