题解 | #密码截取#

密码截取

http://www.nowcoder.com/practice/3cd4621963e8454594f00199f4536bb1

题目的主要信息:

  • 输入一个长度不超过2500的字符串
  • 找到其中最长的回文子串长度

方法一:中心扩散法

具体做法:

我们可以遍历每个字符串每个位置,都以其为回文子串的中心,或是奇数长度子串的中心(从两边开始找),或是偶数长度的子串中心(以它左边和它一起),分别向两边扩散,只要这个过程中两边字符是相等的就可以继续,直到边界或者不相等,这就是以这个为中心的回文子串的长度,我们比较每一个中心找到最长即可。

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

int main(){
    string s;
    while(cin >> s){
        int maxlen = 0;
        for(int i = 1; i < s.length(); i++){ //每个点都可以为中心
            //计算以i-1和i为中心的偶数长度的回文子串长度
            int low = i - 1, high = i;
            while(low >= 0 && high < s.length() && s[low] == s[high]){ //中心两边必须都相同
                low--;
                high++;
            }
            maxlen = max(maxlen, high - low - 1); 
            //计算以i为中心的奇数长度的回文子串长度
            low = i - 1, high = i + 1;
            while(low >= 0 && high < s.length() && s[low] == s[high]){ //中心两边必须都相同
                low--;
                high++;
            }
            maxlen = max(maxlen, high - low - 1);
        }
        cout << maxlen << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n2)O(n^2),外循环遍历每个点,内循环最坏情况下遍历半个字符串长度
  • 空间复杂度:O(1)O(1),无额外空间

方法二:动态规划

具体做法:

我们用二维数组构建子串回文情况,其中dp[j][i]=1dp[j][i]=1表示从jjii满足回文子串的要求,则有转移方程: alt

第一种情况是看以这个位置为中心的奇数长度的回文子串,第二种情况是以这两个位置为中心的偶数长度回文子串,第三种情况是这是边界,看中间是否是回文子串。最后找到最大的iijj的距离即可。 alt

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;

int main(){
    string s;
    while(cin >> s){
        int n = s.length();
        vector<vector<bool> > dp(n, vector<bool>(n, false)); //dp[j][i]=1表示从j到i是回文子串
        int maxlen = 1; //初始为1
        for(int i = 0; i < n; i++){
            for(int j = 0; j <= i; j++){
                if(i == j) //奇数长度子串
                    dp[j][i] = true;
                else if(i - j == 1) //偶数长度子串
                    dp[j][i] = (s[i] == s[j]);
                else
                    dp[j][i] = (s[i] == s[j] && dp[j + 1][i - 1]); //这两个字符相等,同时中间缩也要相等
                if(dp[j][i] && i - j + 1 > maxlen) //取最大
                    maxlen = i - j + 1;
            }
        }
        cout << maxlen << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n2)O(n^2),遍历二维数组
  • 空间复杂度:O(n2)O(n^2),辅助空间为二维数组
孤帆远影碧空尽 文章被收录于专栏

牛客网各类题单题解~

全部评论
因为匹配后low和high又都--了,所以就是high-low-1
1 回复 分享
发布于 2023-05-14 13:32 江苏
dp示意图第二行的条件(即偶数情况)应该是i-j = 1; 证:两层for循环中i是外层,第二层for循环中的循环边界条件是j < i;
点赞 回复 分享
发布于 2023-07-02 11:55 浙江
maxlen = max(maxlen, high - low - 1);? 为啥不是maxlen = max(maxlen, high - low + 1); 长度不是high - low + 1吗?
点赞 回复 分享
发布于 2022-06-02 16:45

相关推荐

12-24 14:26
东北大学 Java
一只乌鸦:重邮+东北,好经典的学校
最后再改一次简历
点赞 评论 收藏
分享
12-14 11:43
黑龙江大学 Java
用微笑面对困难:确实比较烂,可以这么修改:加上大学的qs排名,然后大学简介要写一些,然后硕士大学加大加粗,科研经历第一句话都写上在复旦大学时,主要负责xxxx,简历左上角把学校logo写上,建议用复旦大学的简历模板
点赞 评论 收藏
分享
11-05 10:55
中南大学 Java
要双修的猫头鹰:这面试官怕不是个m
我来点评面试官
点赞 评论 收藏
分享
评论
43
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务