Leetcode - Longest Palindromic Substring

Question:

Paste_Image.png

My code:

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0)
            return null;
        int max = 1;  // assume that every single character is palindrome
        String longestStr = "" + s.charAt(0);
        for (int i = 0; i < s.length() - 1; i++) {
            String s1 = getP(s, i, i);
            if (max < s1.length()) {
                max = s1.length();
                longestStr = s1;
            }
            String s2 = getP(s, i, i + 1);
            if (max < s2.length()) {
                max = s2.length();
                longestStr = s2;
            }
        }
        return longestStr;
    }
    
    private String getP(String s, int head, int tail) {
        int i = head;
        int j = tail;
        while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
            i--;
            j++;
        }
        return s.substring(i + 1, j);
    }
    
    
    public static void main(String[] args) {
        Solution test = new Solution();
        String a = "abb";
        System.out.println(test.longestPalindrome(a));
    }
}

My test result:

Paste_Image.png

这次题目做了好久。。。每次都是时间测试过不了。
第一次我使用了自己的算法。用一个哈希数组来处理。
我的做法是申请一个二维数组:


Paste_Image.png

用来标志每个字符在字符串中出现的index。这个二维数组的功能相当于一个哈希表。所以首先需要遍历下字符串,复杂度是 O(n),构造这个二维数组。然后再次遍历整个字符串。比如遍历到的是 'a',就去二维数组中直接定位到存放'a'的那个内存块。然后判断所有这些位置是否能构成回环。因为开头是'a'的回环字符串,其结尾也一定是'a'。所以用这个二维数组充当哈希表,快速的找出该字母在字符串中出现的位置,然后判断这些情况是否构成回环。

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0)
            return null;
        int max = 1;  // assume that every single character is palindrome
        String longestStr = "" + s.charAt(0);
        int[][] hashArray = new int[256][s.length()];  // to state the index of every character in this string
        int[] frequency = new int[256];  // to state the times that every character comes up
        for (int i = 0; i < s.length(); i++)
            hashArray[s.charAt(i)][frequency[s.charAt(i)]++] = i;
        for (int i = 0; i < s.length(); i++) {
            for (int j = frequency[s.charAt(i)] - 1; j >= 0; j--) {
                if (i >= hashArray[s.charAt(i)][j])
                    continue;
                else {
                    if (isPalindrome(s, i, hashArray[s.charAt(i)][j])) {
                        if (hashArray[s.charAt(i)][j] - i + 1 > max) {
                            max = hashArray[s.charAt(i)][j] - i + 1;
                            longestStr = s.substring(i, hashArray[s.charAt(i)][j] + 1);
                            break;
                        }
                    }
                        
                }
            }
            if (max >= s.length() - i)
                break;
        }
        return longestStr;
    }
    
    private boolean isPalindrome (String s, int head, int tail) {
        if (head < 0 || head >= s.length() || tail < 0 || tail >= s.length())
            return false;
        int i = head;
        int j = tail;
        while (i <= j) {
            if (s.charAt(i) != s.charAt(j))
                return false;
            else {
                i++;
                j--;
            }
        }
        
        return true;
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        String a = "civilwartestingwhetherthatnaptionoranynartionsoconceivedandsodedicatedcanlongendureWeareqmetonagreatbattlefiemldoftzhatwarWehavecometodedicpateaportionofthatfieldasafinalrestingplaceforthosewhoheregavetheirlivesthatthatnationmightliveItisaltogetherfangandproperthatweshoulddothisButinalargersensewecannotdedicatewecannotconsecratewecannothallowthisgroundThebravelmenlivinganddeadwhostruggledherehaveconsecrateditfaraboveourpoorponwertoaddordetractTgheworldadswfilllittlenotlenorlongrememberwhatwesayherebutitcanneverforgetwhattheydidhereItisforusthelivingrathertobededicatedheretotheulnfinishedworkwhichtheywhofoughtherehavethusfarsonoblyadvancedItisratherforustobeherededicatedtothegreattdafskremainingbeforeusthatfromthesehonoreddeadwetakeincreaseddevotiontothatcauseforwhichtheygavethelastpfullmeasureofdevotionthatweherehighlyresolvethatthesedeadshallnothavediedinvainthatthisnationunsderGodshallhaveanewbirthoffreedomandthatgovernmentofthepeoplebythepeopleforthepeopleshallnotperishfromtheearth";
        System.out.println(test.longestPalindrome(a));
    }
}

然后时间测试过不了。
于是我参考了网上的做法,使用DP。
具体代码:

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0)
            return null;
        int max = 1;  // assume that every single character is palindrome
        String longestStr = "" + s.charAt(0);
        int left = 0;
        int right = 1;
        boolean[][] isPal = new boolean[1000][1000];
        for (int i = 0; i < s.length(); i++)
            isPal[i][i] = true;
        for (int i = 0; i < s.length() - 1; i++) {
            if (s.charAt(i) == s.charAt(i + 1)) {
                isPal[i][i + 1] = true;
                left = i;
                right = i + 1;
            }
        }
        for (int len = 3; len < s.length(); len++) {
            for (int i = 0; i < s.length() - len + 1; i++) {
                int j = i + len - 1;
                if (s.charAt(i) == s.charAt(j) && isPal[i + 1][j - 1]) {
                    isPal[i][j] = true;
                    left = i;
                    right = j + 1;
                }
            }
        }
        
        return s.substring(left, right);
        
        
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        String a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        System.out.println(test.longestPalindrome(a));
    }
}

时间测试过不了,于是我采用了最上面的那个方法。
其实还有一个O(n)复杂度的方法,今晚太累,看不动了,以后有机会再研究。
这四个方法在两篇别人的日志里写的很好,链接如下
https://github.com/xiangzhai/leetcode/blob/master/question/longest-palindromic-substring-part-i.md

https://github.com/xiangzhai/leetcode/blob/master/question/longest-palindromic-substring-part-ii.md

有兴趣的可以具体看下。

**
总结: 妈了个逼的真恶心。。。
然后,我想说,其实申明数组也是很花时间的。
比如说,我觉得第二个做法过不了时间测试而第三个可以过的原因就是,第二个做法申明了一个二维数组。
a[1000][1000].申明这个数组的时候,编译器会自动执行

for (int i = 0; i < 1000; i++)
    for (int j = 0; j < 1000; j++)
         a[i][j] = 0;

会花费一些时间。
然后经确认, s.charAt(i) 复杂度是 O(1)
**

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0)
            return s;
        int maxLen = Integer.MIN_VALUE;
        String maxStr = null;
        for (int i = 0; i < s.length(); i++) {
            /** choose i as center, move left and right: (pre, post) */
            int pre = i - 1;
            int post = i + 1;
            while (pre >= 0 && post < s.length() && s.charAt(pre) == s.charAt(post)) {
                pre--;
                post++;
            }
            if (post - pre - 1 > maxLen) {
                maxLen = post - pre - 1;
                maxStr = s.substring(pre + 1, post);
            }
            /** choose i, i+1 as center, move left and right: (pre, post) */
            pre = i;
            post = i + 1;
            while (pre >= 0 && post < s.length() && s.charAt(pre) == s.charAt(post)) {
                pre--;
                post++;
            }
            if (post - pre - 1 > maxLen) {
                maxLen = post - pre - 1;
                maxStr = s.substring(pre + 1, post);
            }
            if (maxLen == s.length())
                break;
        }
        return maxStr;
    }
}

这个作法的思想就是以i为中点,向左右扩散。
然后有两种可能。
(..., i - 1, i, i + 1, ....)
(..., i - 1, i , i + 1, i + 2, ....)
然后判断下,如果已经达到了最大值,就直接退出循环了。
复杂度是O(n^2)

第二种做法:
My code:

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0)
            return s;
        int maxLen = Integer.MIN_VALUE;
        String maxStr = null;
        int[][] tracker = new int[s.length()][s.length()];
        /** for palindromic string with length 1 */
        for (int i = 0; i < s.length(); i++)
            tracker[i][i] = 1;
        /** for palindromic string with length 2 */
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i - 1) == s.charAt(i)) {
                tracker[i - 1][i] = 1;
                maxLen = 2;
                maxStr = s.substring(i - 1, i + 1);
            }
        }
        /** for palindromic string with length >= 3, <= s.length() 
        * if tracker[i + 1][i + j - 1] == 1 and s.charAt(i) == s.charAt(i + j) => tracker[i][i + j] = 1;
        */
        for (int j = 2; j < s.length(); j++) {
            for (int i = 0; i + j < s.length(); i++) {
                if (tracker[i + 1][i + j - 1] == 1 && s.charAt(i) == s.charAt(i + j)) {
                    tracker[i][i + j] = 1;
                    if (maxLen < j + 1) {
                        maxLen = j + 1;
                        maxStr = s.substring(i, i + j + 1);
                    }
                }
            }
        }
        return maxStr;
    }
}

DP. 设置一个二维矩阵,一层层推进过去。
但是,时间测试过不了。因为他的复杂度一定是 n ^ 2
而上一种做法,系数可能会小很多,所以过了测试。

还有种做法复杂度是 O(n), 就不研究了。
参考网址:
http://www.programcreek.com/2013/12/leetcode-solution-of-longest-palindromic-substring-java/

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return s;
        }
        
        int len = s.length();
        int maxLen = 1;
        String ret = "" + s.charAt(0);
        for (int i = 0; i < len; i++) {
            int begin = i;
            int end = i;
            while (begin - 1 >= 0 && end + 1 < len && s.charAt(begin - 1) == s.charAt(end + 1)) {
                begin--;
                end++;
            }
            if (maxLen < end - begin + 1) {
                maxLen = end - begin + 1;
                ret = s.substring(begin, end + 1);
            }
            
            begin = i;
            end = i + 1;
            while (begin >= 0 && end < len && s.charAt(begin) == s.charAt(end)) {
                begin--;
                end++;
            }
            if (maxLen < end - begin - 1) {
                maxLen = end - begin - 1;
                ret = s.substring(begin + 1, end);
            }
        }
        
        return ret;
    }
}

第一种中间扩散的方法,和上面的一样,不多写了。
然后DP做法,其实很简单,我想的过于复杂了。

My code:

public class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return s;
        }
        
        int len = s.length();
        boolean[][] dp = new boolean[len][len];
        int maxLen = 0;
        String ret = "" + s.charAt(0);
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }
        for (int i = 0; i < len - 1; i++) {
            if (s.charAt(i) == s.charAt(i + 1)) {
                dp[i][i + 1] = true;
                maxLen = 2;
                ret = s.substring(i, i + 2);
            }
        }
        
        for (int k = 3; k <= len; k++) {
            for (int i = 0; i <= len - k; i++) {
                int j = i + k - 1;
                if (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = true;
                    if (j - i + 1 > maxLen) {
                        maxLen = j - i + 1;
                        ret = s.substring(i, j + 1);
                    }
                }
            }
        }
        
        return ret;
    }
}

其实只是起到了 memcache 的作用。

Anyway, Good luck, Richardo! -- 09/18/2016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容