leetcode上两道关于回文字符串的题解


这两道题都是关于回文串的题目。

之前在语言入门的时候,我们做过 判断一个字符串是否回文,我们知道可以用双指针的方法解法:即左右夹逼,往中间靠拢,找出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};
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

通信仿真爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值