• 【LeetCode-字符串】最长回文子串


    题目描述

    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
    示例:

    输入: "babad"
    输出: "bab"
    注意: "aba" 也是一个有效答案。
    
    输入: "cbbd"
    输出: "bb"
    

    题目链接: https://leetcode-cn.com/problems/longest-palindromic-substring/

    思路1

    暴力法。求出所有的子串,然后判断子串是否是回文串,保留最长的回文串。代码如下:

    class Solution {
    public:
        string longestPalindrome(string s) {
            if(s.empty()) return "";
            if(s.length()==1) return s;
    
            string ans = "";
            for(int i=0; i<s.length(); i++){
                for(int j=0; j<=s.length()-i; j++){
                    string ss = s.substr(i,j);
                    if(ss.length()>ans.length() && isOk(ss)){
                        ans = ss;
                    }
                }
            }
            return ans;
        }
    
        bool isOk(string s){
            int left=0;
            int right=s.length()-1;
            while(left<right){
                if(s[left]!=s[right]){
                    return false;
                }
                left++;
                right--;
            }
            return true;
        }
    };
    
    • 时间复杂度:O(n^3)
      外面两层循环,中间的substr应该也要O(n)(没搜到substr的时间复杂度),所以为O(n^3)。
    • 空间复杂度:O(1)

    该方法超时未通过。

    思路2

    如果一个字符串是回文串,那么从该字符串中心开始左右是对称的。所以,我们可以遍历字符串,当遍历到某个字符时,设置两个指针,以该字符为中心向左右扩展,并统计左右两边相等的字符个数,也就是回文串的长度。需要注意的是,当字符串长度为奇数时,如aba,则两个指针都从b开始扩展即可;如果字符串长度为偶数,如abba,这样如果两个指针都从同一位置开始则找不到回文串,尽管该字符串就是一个回文串。为了避免这个问题,对于每个字符我们要左右扩展两次:第一次左右指针从同一位置出发,第二次右指针从左指针的下一个位置出发(i和i+1)。代码如下:

    class Solution {
    public:
        string longestPalindrome(string s) {
            if(s.empty()) return "";
            if(s.length()==1) return s;
    
            int maxLen = -1;
            string ans = "";
            int start=0, end=0;
            for(int i=0; i<s.length(); i++){
                int len1 = spanAroundCenter(s, i, i);
                int len2 = spanAroundCenter(s, i, i+1);
                int len = max(len1, len2);
                if(len>maxLen){
                    maxLen = len;
                    if(len2>len1){
                        start = i-len/2+1;    // 注意这个
                        end = i+len/2;
                    }else{
                        start = i-len/2;
                        end = i+len/2;
                    }
                }
            }
            return s.substr(start, end-start+1);
        }
    
        int spanAroundCenter(string s, int left, int right){
            int len = 0;
            while(left>=0 && right<s.length()){
                if(s[left]==s[right]){
                    len++;
                } else return right-left-1; // 不能直接返回len,直接返回len无法区别是哪种扩展方式
                left--;
                right++;
            }
            return right-left-1;
        }
    };
    
    • 时间复杂度:O(n^2)
    • 空间复杂度:O(1)

    更简洁的写法
    下面的写法更加简洁,也更快:

    class Solution {
    public:
        string longestPalindrome(string s) {
            if(s.empty()) return "";
            if(s.length()==1) return s;
    
            int n = s.length();
            string ans = "";
            string temp = "";
            int curMaxLen = -1;
            for(int center=0; center<2*n-1; center++){
                int left = center/2;
                int right = left+center%2;
    
                while(left>=0 && right<n && s[left]==s[right]){
                    if(right-left+1>curMaxLen){ // right-left+1是当前的字符串长度
                        ans = s.substr(left, right-left+1);
                        curMaxLen = right-left+1;
                    }
                    left--;
                    right++;
                }
            }
            return ans;
        }
    };
    

    这样写更容易理解:

    class Solution {
    public:
        string longestPalindrome(string s) {
            if(s.empty()) return s;
    
            int n = 2*s.size()-1;
            string ans = "";
            for(int i=0; i<n; i++){
                int left = i/2;
                int right = (i+1)/2;
                while(left>=0 && right<s.size() && s[left]==s[right]){
                    left--;
                    right++;
                }
                left++;
                right--;
                if(ans.size()<right-left+1){
                    ans = s.substr(left, right-left+1);
                }
            }
            return ans;
        }
    };
    

    相关题目

    1、回文子串:https://www.cnblogs.com/flix/p/12810171.html

  • 相关阅读:
    Android学习笔记(四十):Preference的使用
    我的Android笔记(十一)——使用Preference保存设置
    Vim简明教程【CoolShell】
    普通人的编辑利器——Vim
    终端shell显示当前git分支_修订版
    代码规范须知_V1.0_20140703
    Android 4.4源码编译过程
    一个帖子学会Android开发四大组件
    什么是软件质量?
    软件配置管理的作用?软件配置包括什么?
  • 原文地址:https://www.cnblogs.com/flix/p/12692867.html
Copyright © 2020-2023  润新知