[LeetCode] 5. Longest Palindromic Substring

版权声明:如需转载请注明出处 https://blog.csdn.net/Bertram03/article/details/87169555

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

1. 题目介绍

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: “babad”
Output: “bab”
Note: “aba” is also a valid answer.

Example 2:

Input: “cbbd”
Output: “bb”

输入一个字符串,输出这个字符串中最长的回文串。

2. 解题思路

2.1 动态规划法

P(i,j)代表着从第i个字符到第j个字符的子串。
判断P(i,j)是回文串的标志就是 第i个字符==第j个字符,并且P(i+1,j-1)也是回文串,于是使用二维数组dp,记录P(i,j)的值。

注意
在测试样例中有一个空样例,需要加入判断样例是否为空的语句。
在这里插入图片描述
实现代码

class Solution {
    public String longestPalindrome(String s) {
		
        int length = s.length();
        if(s == null || length == 0) {
        	return "";
        }
   
        String res = null;
        boolean dp[][] = new boolean[length][length];
        int Max = 0;//最长回文串的长度,初值为零
        
        for(int i = length-1;i>=0;i--) {
        	for(int j = i;j<length;j++) {
        		if(s.charAt(i) == s.charAt(j) && (j-i<2 || dp[i+1][j-1]) ) {
        		/*
        		 * 这里的j-i<2 包括两种情况
        		 * 1. j==i,这两个是同一个字符
        		 * 2. j=i+1,这两个是连在一起的两个相同字符,如aa
        		 * */
        		
        			dp[i][j] = true;
        		}
        		
        		if(dp[i][j] == true && j-i+1 >Max) {
        			Max = j-i+1;
        			res = s.substring(i,j+1);
        		}
        	}
        }
        return res;
    }
}

上述代码的执行时间是58ms
在这里插入图片描述

在LeetCode上,用户EthanXiaoMa指出,上述代码中,时间复杂度看似为O(n ^ 2),但是由于String的 substring 方法的复杂度是 O(n), 所以上述代码的实际复杂度是O(n ^ 3)。

因此可以采用一个小技巧,记录最大值对应的 i 、j,只在return时才调用substring方法。这样时间复杂度才是真正的 O(n^2),经过改进的代码执行时间为36ms,执行时间短了很多。
在这里插入图片描述

改进代码

class Solution {
	public String longestPalindrome(String s) {
		
        int length = s.length();
        if(s == null || length == 0) {
        	return "";
        }
   
        String res = null;
        boolean dp[][] = new boolean[length][length];
        int Max = 0;//最长回文串的长度,初值为零
        int start=0, end=0;//记录最长回文串的起始位置
        
        for(int i = length-1;i>=0;i--) {
        	for(int j = i;j<length;j++) {
        		if(s.charAt(i) == s.charAt(j) && (j-i<2 || dp[i+1][j-1]) ) {
        		/*
        		 * 这里的j-i<2 包括两种情况
        		 * 1. j==i,这两个是同一个字符
        		 * 2. j=i+1,这两个是连在一起的两个相同字符,如aa
        		 * */
        		
        			dp[i][j] = true;
        		}
        		
        		if(dp[i][j] == true && j-i+1 >Max) {
        			Max = j-i+1;
        			start = i;
        			end = j;
        		}	
        	}
        }
        res = s.substring(start, end+1);
        return res;
    }	
}

2.2 中心拓展法

这是LeetCode的solution给出的解法之一,速度最快,时间复杂度O(n^2),可以在10ms完成。

每一个回文串都有一个中心,aba的中心是a,aaaa的中心在第2个a和第3个a之间的空隙。对于一个长度为n的字符串来说,中心的数目有2n-1个(字符和空隙都算)。

因此从头遍历每一个“中心”,从每一个中心向两边拓展,谁拓展的最多,谁就是最长回文串。
下面的实现代码来自 https://leetcode.com/problems/longest-palindromic-substring/solution/
实现代码

class Solution {
   public String longestPalindrome(String s) {
    if (s == null || s.length() < 1) return "";
    int start = 0, end = 0;
    for (int i = 0; i < s.length(); i++) {
        int len1 = expandAroundCenter(s, i, i);
        int len2 = expandAroundCenter(s, i, i + 1);
        int len = Math.max(len1, len2);
        if (len > end - start) {
            start = i - (len - 1) / 2;
            end = i + len / 2;
        }
    }
    return s.substring(start, end + 1);
}

private int expandAroundCenter(String s, int left, int right) {
    int L = left, R = right;
    while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
        L--;
        R++;
    }
    return R - L - 1;
}
}

3. 参考资料

动态规划法:
https://leetcode.com/problems/longest-palindromic-substring/discuss/2921/Share-my-Java-solution-using-dynamic-programming
中心拓展法:
https://leetcode.com/problems/longest-palindromic-substring/solution/

猜你喜欢

转载自blog.csdn.net/Bertram03/article/details/87169555