力扣——最长回文子串

题目链接:

链接

题目描述:

力扣——最长回文子串_第1张图片

思路:

思路一

有以下几种情况:

  1. 子串长度为1,只有一个字母,是回文串
  2. 子串长度为2,如果这两个字母相同,是回文串
  3. 子串长度为3,中间的部分一定是回文串,如果边界的两个字母相同,是回文串(可以看成情况2或情况4)
  4. 子串长度>=4,如果 边界字母相同&&中间的字串是回文串,是回文串

我们需要知道子串 [ i , j ] [i,j] [i,j]是否是回文串,设 d p ( i , j ) dp(i,j) dp(i,j)表示字串是否为回文串,是则为true,否则为false,字串的长度为 l = j − i + 1 l = j - i +1 l=ji+1
则: 当 l = 1 , d p ( i , i ) = t r u e 当 l = 2 或 3 , d p ( i , j ) = s ( i ) = = s ( j ) 当 l > 3 , d p ( i , j ) = d p ( i + 1 , j − 1 ) & & s ( i ) = = s ( j ) 当l = 1,dp(i,i) = true \\ 当l = 2 或 3,dp(i ,j) = s(i)==s(j)\\ 当l >3,dp(i, j) = dp(i+1,j-1) \&\& s(i)==s(j) l=1dp(i,i)=truel=23dp(i,j)=s(i)==s(j)l>3dp(i,j)=dp(i+1,j1)&&s(i)==s(j)

只用一个行向量是无法表示全部dp情况的,所以需要一个矩阵[i,j],i<=j,是一个上三角矩阵

思路二

中心扩展法
中心有两种情况:

  1. 一个字母
  2. 两个相等的字母

由这两种情况不断向外扩展就行,只要两边的字母相等,就是回文串

  • 关于最后开头结尾索引的计算
    e n d − s t a r t + 1 = l e n i = s t a r t + ( e n d − s t a r t ) / 2 = s t a r t + ( l e n − 1 ) / 2 s t a r t = i − ( l e n − 1 ) / 2 end - start+1 = len\\ i = start + (end - start)/2 = start+(len-1)/2\\ start = i - (len-1)/2\\ endstart+1=leni=start+(endstart)/2=start+(len1)/2start=i(len1)/2
    按照上面的思路
    e n d = i + ( l e n − 1 ) / 2 end= i + (len-1)/2 end=i+(len1)/2
    但是在偶数个数情况下,如【0 1 1 0】,len = 4,i =1, end = 1 +(4-1)/ 2 = 1 + 1 = 2,实际等于3,所以
    e n d = i + l e n / 2 end= i + len/2 end=i+len/2

实现代码:

class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        //长度为1,就是本身
        if(n < 2){
            return s;
        }

        int maxLen = 1;
        int left = 0;
        boolean[][] dp = new boolean[n][n];
		//对角线上的一定是true
        for(int i = 0; i < n; i++){
            dp[i][i] = true;
        }
        
        char[] charArray = s.toCharArray();
        //按照长度遍历
        for(int l = 2; l <= n; l++){
        	//按照开始位置遍历
            for(int i = 0; i < n; i++){
                int j = i + l - 1;
                //j表示字串结束的位置
                if(j >= n){
                    break;
                }
                //两边的不一样,一定是false
                if(charArray[i] != charArray[j]){
                    dp[i][j] = false;
                }else{
                	//长度是2或3,只要两边的相同,一定是true
                    if(l <= 3){
                        dp[i][j] = true;
                    }else{
                    	//其他情况下要看中间部分
                        dp[i][j] = dp[i+1][j-1];
                    }
                }
				//是回文串且长度更大,就更新数值
                if(dp[i][j] && l > maxLen){
                    maxLen = l;
                    left = i;//回文串的开头
                }
            }
        }

        return s.substring(left,left + maxLen);
    }
}
class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        if(n < 2){
            return s;
        }

        int start = 0 ,end = 0;//代表开头和结尾的索引
        for(int i = 0; i < n; i++){
            int len1 = expand(s,i,i); //根据1个字母向外扩展
            int len2 = expand(s,i,i+1);//根据2个字母向外扩展
            int len = len1 > len2 ? len1 : len2;
            if(len > end - start +1){//新的长度更大
                start = i - (len - 1)/2; //因为是从i开始,i更靠近开头,经过公式推导就需要len-1
                end = i + len/2;//因为i更靠近开头,所以找结尾的索引不需要减1
            }
        }
        return s.substring(start , end + 1);
    }
    public int expand(String s, int left, int right){
        while(left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        //返回的应该是right-1 和 left+1之间的长度,
        //因为上面执行了++--不符合条件了,
        //所以应该返回上一次符合条件的值 len = (right-1) - (left+1) + 1
        return right - left - 1; 
    }
}

你可能感兴趣的:(力扣,leetcode,算法,职场和发展)