美文网首页动态规划计算机
Leetcode - Longest Palindromic S

Leetcode - Longest Palindromic S

作者: Richardo92 | 来源:发表于2015-07-05 01:46 被阅读62次

    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

    相关文章

      网友评论

        本文标题:Leetcode - Longest Palindromic S

        本文链接:https://www.haomeiwen.com/subject/tleyqttx.html