Leetcode 5. Longest Palindromic Substring [medium][Java]

5. 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.

Example:
Leetcode 5. Longest Palindromic Substring [medium][Java]_第1张图片

Key Point

  1. a palindromic substring is symmetric at its centre, so we need to start from the centre and every time treat the indexed character as the centre.
  2. For current centre index I, there are two cases:(a) the length of the palindromic substring is odd, so let the initial value of left and right index be the same, which is i; (b) the length is even, so let the initial value of left be I and let the right index be I+1. Move the left pointer to left and move the right pointer to right.

Solution 1: Expand Around Center.
Time complexity: O(n^2), space complexity: O(1)

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length()<=1)
            return s;

        
        int start = 0;
        int end = 0;
        
        for(int i = 0; i < s.length(); i++) {
            int left = i; 
            int right = i;
            while(left!=-1 && right!=s.length() && s.charAt(left)==s.charAt(right)) {
                left--;
                right++;
            }
            if((right-left) > (end-start)) {
                start = left;
                end = right;
            }
            
            left = i; 
            right = i+1;
            while(left!=-1 && right!=s.length() && s.charAt(left)==s.charAt(right)) {
                left--;
                right++;
            }
            if((right-left) > (end-start)) {
                start = left;
                end = right;
            }
            
        }
        return s.substring(start+1,end);
    }

}

Solution 2: Brute Force, time complexity: O(n^3), space complexity: O(1)
Ignored Cases
Leetcode 5. Longest Palindromic Substring [medium][Java]_第2张图片
Leetcode 5. Longest Palindromic Substring [medium][Java]_第3张图片

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.equals(""))
            return s;
        
        int start = 0;
        int end = 0;
        
        for(int i = 0; i < s.length(); i++) 
            //j should be not less than i
            for(int j = s.length()-1; j >= i; j--) {
                if( isPalindrome(s,i,j)&&(j-i) >(end-start)) {
                    start = i;
                    end = j;
                }
            }
        return s.substring(start,end+1);
    }
    
    
    public boolean isPalindrome(String s, int start, int end) {
        if(start >= end)
            return true;
        
        if(s.charAt(start) != s.charAt(end)) 
            return false;
        return isPalindrome(s, start+1, end-1);
    }
    
}

Solution 3: Brute Force, but start from the longest search length, so once found, immediately return the result
Time Complexity: O(n^3), Space Complexity: O(1)

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.equals(""))
            return s;
        
        for(int len = s.length(); len > 0; len--) {
            for(int i = 0; i <= s.length()-len; i++) {
                 if( isPalindrome(s,i,i+len-1))
                     return s.substring(i,i+len);
            }
        }

        return null;
    }
    
    
    public boolean isPalindrome(String s, int start, int end) {
        if(start >= end)
            return true;
        if(s.charAt(start) != s.charAt(end)) 
            return false;
        return isPalindrome(s, start+1, end-1);
    }
    
}

Solution 4: Dynamic Programming, we can compare each pair of characters and store them in a 2D array.
Time Complexity: O(n^2). Space Complexity: O(n^2)
Consideration:

  1. We create a n*n size array d to compare the character comparison result
  2. Firstly, initialise the value for d[i][i]
  3. Then, initialise the value when d[i][j]
  4. Then start from length 3, for each i and j, its comparison is done by character[i]=character[j] and d[i+1][j-1]
class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length()<=1)
            return s;

        int len = s.length();
        int maxLen = 1;
        int maxStart = 0;
        boolean[][] d = new boolean[len][len];
        
        for(int i = 0; i < len; i++) {
            d[i][i] = true;
        }
        
        char[] chars = s.toCharArray();
        for(int i = 0; i < len-1; i++) {
            if(chars[i] == chars[i+1]) {
                d[i][i+1] = true;
                if(maxLen < 2) {
                    maxLen = 2;
                    maxStart = i;
                }
            } else {
                d[i][i+1] = false;
            }
                
        }
        
        
        for(int j = 2; j < len; j++) {
            // i should be less than j-1, since the condition for d[i][i+1] has been considered previously
            for(int i = 0; i < j-1; i++) {
                d[i][j] = (chars[i]==chars[j] && d[i+1][j-1]);
                if(d[i][j] && j-i+1 > maxLen) {
                    maxLen = j-i+1;
                    maxStart = i;
                } 
            }
        }
        
        return s.substring(maxStart, maxStart+maxLen);
    }
}

Solution 5: Manacher’s algorithm
Time Complexity: O(n), Space Complexity: O(n)
References: https://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html

class Solution {
    public String longestPalindrome(String s) {
        if(s==null || s.length() <=1) {
            return s;
        }
        
        String T = preProcess(s);
        int R = 0;
        int C = 0;
        int len = T.length();
        int[] P = new int[len];
        
        for(int i = 1; i < len-1; i++) {
            int i_mirror = C-(i-C);
            int diff = R-i;
            if(diff < 0) {// i is out the range of [L,R]
                //recalculate the palindrome length
                P[i] = 0;
                while(T.charAt(i-P[i]-1) == T.charAt(i+P[i]+1))
                    P[i]++;
                C = i;
                R = i+P[i]-1;  
            } else {
                if(P[i_mirror] <= diff) {//the palindrome length centered at i_mirror is less than the maximal palindrome length centered at C
                    P[i] = P[i_mirror];
                } else {
                    P[i] = diff;
                    while(T.charAt(i-P[i]-1) == T.charAt(i+P[i]+1))
                        P[i]++;
                    C = i;
                    R = i+P[i]-1;  
                }
            }
        }
            
        int maxLen = 0;
        int maxCen = 0;
        for(int i = 1; i < len-1; i++) {
            if(P[i] > maxLen) {
                maxLen = P[i];
                maxCen = i;
            }
        }
            
        return s.substring((maxCen-1-maxLen)/2, (maxCen-1-maxLen)/2+maxLen);
            
        
        
    }
    
    
    
    public String preProcess(String s) {
        String T = "^";
        for(int i = 0; i < s.length(); i++)
            T+="#"+s.charAt(i);
        T += "#$";
        return T;
    }
}

== Solution 6: Longest Common Substring==
Time Complexity: O(n^2), Space Complexity:O(n^2)
Considerations

  1. we reverse the original string s to revS
  2. we find the longest common substring of s and revS
  3. once found, we check if the indices in the revS equal to the indices in s
class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length()<=1)
            return s;

        
        String revS = new StringBuilder(s).reverse().toString();
        int len = s.length();
        int[][] arr = new int[len][len];
        int maxLen = 0;
        int maxEnd = 0;
        
        for(int i = 0; i < len; i++) {
            for(int j = 0; j < len; j++) {
                if(revS.charAt(j) == s.charAt(i)) {
                    if(i==0||j==0)
                        arr[i][j] = 1;
                    else
                        arr[i][j] = arr[i-1][j-1]+1;
                        
                } else {
                    arr[i][j] = 0;
                }
                
                // both i and j point to the end of the array
                // we should find whether the end index of the substring in revS equals to i
                int beforeRev = len-1-j;
                if(i==beforeRev+arr[i][j]-1) {
                    if(arr[i][j] > maxLen) {
                        maxLen = arr[i][j];
                        maxEnd = i;
                    }
                }
            }
        }

                      
                      

        return s.substring(maxEnd+1-maxLen,maxEnd+1);
    }
}

== Solution 7: Longest Common Substring (improved space complexity)==
Time Complexity: O(n^2), Space Complexity:O(n)
Considerations

  1. since for arr[i][j], only arr[i-1][j-1] is needed, we don’t need to store the whole array
class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length()<=1)
            return s;

        
        String revS = new StringBuilder(s).reverse().toString();
        int len = s.length();
        int[] arr = new int[len];
        int maxLen = 0;
        int maxEnd = 0;
        
        for(int i = 0; i < len; i++) {
            for(int j = len-1; j >= 0; j--) {
                if(revS.charAt(j) == s.charAt(i)) {
                    if(i==0||j==0)
                        arr[j] = 1;
                    else
                        arr[j] = arr[j-1]+1;
                        
                } else {
                    arr[j] = 0;
                }
                
                // both i and j point to the end of the array
                // we should find whether the end index of the substring in revS equals to i
                int beforeRev = len-1-j;
                if(i==beforeRev+arr[j]-1) {
                    if(arr[j] > maxLen) {
                        maxLen = arr[j];
                        maxEnd = i;
                    }
                }
            }
        }

        return s.substring(maxEnd+1-maxLen,maxEnd+1);
    }

}

== References==

  1. https://juejin.im/post/5bebd55df265da611e4d35a5

你可能感兴趣的:(Leetcode 5. Longest Palindromic Substring [medium][Java])