leetcode#5

每日leetcode

Posted by Cfeng on May 8, 2019

最长回文子串

题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: “babad” 输出: “bab” 注意: “aba” 也是一个有效答案。

示例 2:

输入: “cbbd” 输出: “bb”

思路

很简单的老题目,dp秒解,后来发现时间有点慢。就用Manacher算法又做了一遍
Manacher算法
模板题,不多介绍 后来发现有个稍作优化的暴力求解。。时间还飞快,惊了

Java实现dp

class Solution {
    String longestPalindrome(String s) {
        int len = s.length();
        if (len <= 1) return s;
        int[][] dp = new int[len][len];
        int resLeft = 0, resRight = 0;
        dp[0][0] = 1;
        for (int i = 1; i < len; i++) {
            dp[i][i] = 1;
            dp[i][i - 1] = 1;
        }
        for (int k = 2; k <= len; k++)//枚举子串长度
            for (int i = 0; i <= len - k; i++)//枚举子串起始位置
            {
                if (s.charAt(i) == s.charAt(i + k - 1) && dp[i + 1][i + k - 2] == 1) {
                    dp[i][i + k - 1] = 1;
                    if (resRight - resLeft + 1 < k) {
                        resLeft = i;
                        resRight = i + k - 1;
                    }
                }
            }
        return s.substring(resLeft, resLeft + resRight - resLeft + 1);
    }
}

执行用时 : 106 ms, 在Longest Palindromic Substring的Java提交中击败了40.86% 的用户
内存消耗 : 74.3 MB, 在Longest Palindromic Substring的Java提交中击败了15.90% 的用户

Java实现Manacher

public String longestPalindrome(String s) {
    int len = s.length();
    if (len <= 1) return s;
    char[] cc = s.toCharArray();
    char[] c = new char[len * 2 + 3];
    c[0] = '!';
    c[len * 2 + 2] = '@';
    c[1] = '#';
    for (int i = 0; i < len; i++) {
        c[i * 2 + 2] = cc[i];
        c[i * 2 + 3] = '#';
    }
    int n = c.length, id = 0, mx = 0;
    int p[] = new int[n + 1];
    for (int i = 1; i < n - 1; i++) {
        if (2 * id - i < 0) {
            p[i] = 1;
        } else {
            p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1;
        }
        while (c[i + p[i]] == c[i - p[i]]) p[i]++;

        if (i + p[i] > mx) {
            mx = i + p[i];
            id = i;
        }
    }
    int maxLen = 0, index = 0;
    for (int i = 1; i < n - 1; i++)
        if (p[i] > maxLen) {
            maxLen = p[i];
            index = i;
        }

    return s.substring((index - maxLen) / 2, (index - maxLen) / 2 + maxLen - 1);
}

执行用时 : 8 ms, 在Longest Palindromic Substring的Java提交中击败了98.88% 的用户
内存消耗 : 35.8 MB, 在Longest Palindromic Substring的Java提交中击败了91.68% 的用户

Java实现大佬代码

class Solution {
     public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        int[] range = new int[2];
        char[] c = s.toCharArray();
        for (int i = 0; i < s.length(); i++) {
            i = find(c, i, range);
        }
        return s.substring(range[0], range[1] + 1);
    }

    private int find(char[] c, int low, int[] range) {
        int max = c.length - 1;
        int high = low;
        while (high < max && c[high + 1] == c[low]) {
            high++;
        }
        int result = high;
        while (low > 0 && high < max && c[low - 1] == c[high + 1]) {
            low--;
            high++;
        }
        if (high - low > range[1] - range[0]) {
            range[0] = low;
            range[1] = high;
        }
        return result;
    }
}

执行用时 : 7 ms, 在Longest Palindromic Substring的Java提交中击败了99.04% 的用户
内存消耗 : 34.9 MB, 在Longest Palindromic Substring的Java提交中击败了95.32% 的用户