[LeetCode] Longest Palindrome Substring 具体分析

Given a string S,
find the longest palindromic substring in S.
You may assume that the maximum length of S is
1000, and there exists one unique longest palindromic substring.

面DP题的考官都是神经病。

。(吐槽)

貌似挺easy出回文的题,那么今天细致分析下DP的做法!!

以解我被DP问题虐成渣渣的心碎感觉。如有错误请指出~

首先。拿了这个题,至少也能够给出一个O(n^3)的算法。2层for循环加每次检查一遍substring是不是回文。

我给出了一个必然超时的代码以供參考。

public String longestPalindrome(String s) {
        if(s==null) return null;
        // String[][] dp= new String[1000][1000];
        // Arrays.fill(dp,1);
        int max=1;
        String result=s.substring(0,1);
        for(int i=0;i<s.length()-1;i++){
            for(int j=i+1;j<s.length();j++){
                String temp=s.substring(i,j+1);
                if(ifPalin(temp)){
                    if(max<temp.length()){
                        max=temp.length();
                        result=temp;
                    }
                    if(max==s.length())
                     return result;
                }
            }
        }

        return result;

    }

    public boolean ifPalin(String s){
        if(s==null) return true;
        int start=0;
        int end=s.length()-1;

        while(start<end){
            if(s.charAt(start++)!=s.charAt(end--)){
                return false;
            }
        }

        return true;
    }

这显然不够。怎样优化?你会想到这样的恶心题。dp那是必定的。

那么要分析回文。必定要考虑到全部的情况。

↑上面Naive的方法超时原因是由于:每次循环,都得看一遍当前子串是不是回文,那么怎样解决这样的反复性的工作呢?

通过对回文性质的分析。我们能够看出来: 假设中间的某一段子串sub是回文,假设sub两側的字符是一样的。那么作为一个总体也是回文。

比如:

abcdcba      : d是回文,cdc那么就是回文。 假设你再想一下。cdc是回文。两側b是一样的,bcdcb也是回文。咦,那么abcdcba就是回文了呗。

通过上个样例我们直接知道了答案。这是特例,那么对于普通情况怎样是好呢?所以第一个思路就是依据顺向的思维推导出来的:

我们申明一个dp[][]来储存状态。 对于dp[i][j]来说, 其意义就是 s.substring(i,j+1)是不是回文。

(1)既然我们不知道哪里为中心。向外拓展就能得到答案。

那么就以每一个字符为中心,向外拓展,保存一个最大的量,问题就攻克了!

我们得初始化下dp, 单个字符是,所以dp[i][i]=true.

但是还有种情况。 abcddcba,中间是两个。不是一个,这也能构成回文,这怎么办。

事实上也好办。我们就看看s.charAt(i)==s.charAt(i+1),假设是,就是回文。我们就set  dp[i][i+1]=true

有了基础的case,我们1层for循环移动中心点,用两个指针start,end,分别拓展这两种情况,来分析回文。就可以找出最大值。

代码例如以下:

 public String longestPalindrome(String s) {
          if(s==null) return null;
	        boolean[][] dp= new boolean[s.length()][s.length()];
	        //define dp[i][j] is if s.substring(i,j+1) is palindrome:
	        int max=1;
	        String result=s.substring(0,1);
	        for(int i=0;i<s.length();i++){
	            dp[i][i]=true;
	        }
	        for(int i=0;i<s.length()-1;i++){
	            if(s.charAt(i)==s.charAt(i+1)){
	                dp[i][i+1]=true;
	                result=s.substring(i,i+2);
	                max=2;
	            }
	        }
	        for(int i=1;i<s.length()-1;i++){
	             int start=i-1,end=i+1;  //aba的情况
	             while(start>=0 && end<=s.length()-1){
	                if(dp[i][i] && s.charAt(start)==s.charAt(end)){
	                    dp[start][end]=true;
	                    if(max<end-start+1){
	                        max=end-start+1;
	                        result=s.substring(start,end+1);
	                    }
	                } else {
	                	break;
	                }
	                start--;end++;
	             }
	             start=i-1;end=i+2;  //abba的情况
	             while(start>=0 && end<=s.length()-1){
	                if(dp[i][i+1] && s.charAt(start)==s.charAt(end)){
	                    dp[start][end]=true;
	                    if(max<end-start+1){
	                        max=end-start+1;
	                        result=s.substring(start,end+1);
	                    }
	                } else{
	                	break;
	                }
	                start--;end++;
	             }
	        }

	        return result;

    }

上面的代码啰嗦了点。应该能简化,我比較懒。。假设理解意思了就好办!

(2)上面的解法事实上不太算dp,我们来考虑下真正的dp解法,但这个有时候非常难想出来。。多琢磨吧。。

至少。假设你看到了这。耐心点再看一些。一定会理解dp解这个题的过程:

dp的思路是用曾经做出来的结果作为基础,然后推导出新的结果。(2)的思路是:利用回文的性质,假设推断dp[i][j]是不是回文。那么要具备什么?

答案是:

1. s.charAt(i)==s.charAt(j)

2. dp[i+1][j-1] 是否为真

(这个代表当前的s.substring(i,j+1)往里面缩一个的substring是否是回文,有点绕。。举例: abccbfee, 假设i=0,j=5,也就是abccbf,dp[i][j]就是说abccbf是不是回文,依据之前的结果,假设s.charAt(i)==s.charAt(j),而且。bccb也是回文,那么dp[i][j]就为真. 这个样例中 a!=f, 尽管dp[i+1][j-1]
(bccb)是回文,那也不能算真)

所以这样dp的精华就体现出来了:通过之前的结果,推导如今!

还有个关键点。就是dp的写法。下午我把dp数组打印了出来,横坐标i从后往前。j是从i 到最后。1代表true,是回文,0反之。

dp里面挺多是从后面来的,当然我们不能记结果,而是要明确为什么这么做。

   

回文的中心多数应该是在中心位置,所以。从后往前走,我们能够利用到之前的结果。 (从前往后走也是一样的,仅仅只是循环的參数要对应的变一下)

然而是上面的条件还不够!假设说dp[i+1][j-1]为假。

但当i和j位置的字符是一致的,而且距离小于等于2的时候,那都是回文,原因是仅仅有3种情况: a (i=j)  aa (i=0,j=1) a*a(i=0,j=2)  *表示随意字符. 所以这样我们能够当做回文。

接着i不动,j接着走,超出了2的距离,也有可能会遇到和i一样的字符,这时候是不是回文?那就得看dp[i+1][j-1]是不是回文,假设是。记录,推断是否超过当前最大长度。

假设超过就替换最长字符串。

看第二张图,那三个1,事实上就是样例中 abccbadd的推导过程, 当i=2的循环。j=2。是回文,记录。 i=2, j=3,“cc” 是回文,继续。 "ccb"不是回文,

以上就是所有的分析,建议看文章的童鞋自己推导一遍过程。仅仅有理解了为什么这么做,才干真正理解dp。从而写出出精炼干净的dp代码

:以下代码是从大神那看到的,拿过来的。

    public String longestPalindrome(String s) {
          if(s==null || s.length()==1) return s;
	        boolean[][] dp= new boolean[s.length()][s.length()];
	        //define dp[i][j] is if s.substring(i,j+1) is palindrome:
	        int max=0;
	        String result=s.substring(0,1);
	        for(int i=s.length()-1;i>=0;i--){
	            for(int j=i;j<s.length();j++){
	                if(s.charAt(i)==s.charAt(j) && ((j-i<=2) || dp[i+1][j-1])){
	                    dp[i][j]=true;
	                    if(max<j-i+1){
	                        max=j-i+1;
	                        result=s.substring(i,j+1);
	                    }
	                }
	            }
	        }
	        return result;
    }

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2024-12-25 22:57:08

[LeetCode] Longest Palindrome Substring 具体分析的相关文章

[LeetCode] Longest Palindrome Substring 详细分析

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 面DP题的考官都是神经病..(吐槽) 貌似挺容易出回文的题,那么今天仔细分析下DP的做法!!以解我被DP问题虐成渣渣的心碎感觉.如有错误请指出~ 首先

[LeetCode] Longest Palindromic Substring [14]

题目 Given a string S, find the longest palindromic substring in S. You may assume that the maximum length ofS is 1000, and there exists one unique longest palindromic substring. 原题链接 解题思路 最长回文字串,相信做过Palindrome Partitioning II 这个题的同学应该可以很快做出来.没错,这个题还可以

LeetCode &quot;Longest Palindromic Substring&quot; - 1D DP

2D DP is an intuitive solution of course, but I got an MLE error, so I simplified it into a 1D DP: class Solution { public: void goDp(vector<int> &dp, int &maxLen, int &is, int &ie, int startLen, int len, string &s) { for(int ile

5.Longest Palindrome substring

/* * 5.Longest Palindrome substring * 2016-4-9 by Mingyang 自然而然的想到用dp来做 * 刚开始自己做的时候分的条件太细,两个index相等,相差小于3,还有其他 * 但这里这个if写的很好,一个代表了所有为true的情况 * 根本不用管为false的情况,因为自然而然为false * */ public String longestPalindrome(String s) { String res = " "; if (s =

Leetcode: Longest Palindromic Substring. java

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 动态规划public class Solution { public String longestPalindrome(String s) { if

最长回文字串 (The longest palindrome substring)

这两天去学了一下,觉得下面那篇文章写的很好,有例子,比较容易懂,所以转一下. 以下内容来自:hihoCoder: 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?” 小Ho奇怪的问道:“什么叫做最长回文子串呢?” 小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文

G.Longest Palindrome Substring

链接:https://ac.nowcoder.com/acm/contest/908/G 题意: A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. For example, ”a”.”aba”.“abba” are palindrome and “abc”.”aabb” are not. Let’s d

Leetcode:Longest Palindromic Substring之详细分析

原题链接:https://leetcode.com/problems/longest-palindromic-substring/ 题目:Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 翻译:求给定

[LeetCode] Longest Palindrome 最长回文串

Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters. This is case sensitive, for example "Aa" is not considered a palindrome here. Note: Assume the leng