zoukankan      html  css  js  c++  java
  • [算法]死磕最长回文子串

    题目

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

    示例 1:

    输入: "babad"
    输出: "bab"
    注意: "aba" 也是一个有效答案。
    示例 2:

    输入: "cbbd"
    输出: "bb"

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/longest-palindromic-substring
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    思路

    思路1

    基于中心点枚举的算法,时间复杂度是O(n^2)。

    先确定中间的点,这里包括两种,中间只有一个元素,或者中间有两个元素。

    思路2

    基于动态规划的算法,时间复杂度 O(n^2),会耗费额外的 O(n^2) 的空间复杂度。

    dp[i][j],i <= j,表示从i到j是否是回文串,

    状态转移方程是dp[i][j] = dp[i + 1][j - 1] && s[i] = s[j]。

    思路3

    使用 Manancher's Algorithm,可以在 O(n) 的时间内解决问题。

    参考资料:https://www.felix021.com/blog/read.php?2040

    这个方法虽然最优,感觉一般人很难想到。

    代码

    方法1

    class Solution {
        public String longestPalindrome(String s) {
            if(s == null || s.length() == 0){
                return "";
            }
            int start = 0, len = 0, longest = 1;
            for (int i = 0; i < s.length(); i++) {
                len = longestPalindromeLength(s, i, i);
                if (len > longest) {
                    longest = len;
                    start = i - len / 2;
                }
    
                len = longestPalindromeLength(s, i, i + 1);
                if (len > longest) {
                    longest = len;
                    start = i - len / 2 + 1;
                }
            }
            return s.substring(start, start + longest);
        }
    
        public int longestPalindromeLength(String s, int left, int right) {
            int len = 0;
            while (left >= 0 && right < s.length()) {
                if (s.charAt(left) != s.charAt(right)) {
                    break;
                }
                len += left == right ? 1 : 2;
                left--;
                right++;
            }
            return len;
        }
    }

    方法2

    class Solution {
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) {
                return "";
            }
            int start = 0, longest = 1;
    
            int n = s.length();
            boolean dp[][] = new boolean[n][n];
    
            for (int i = 0; i < n; i++) {
                dp[i][i] = true;
            }
    
            for (int i = 0; i < n - 1; i++) {
                dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
                if(dp[i][i + 1]){
                    start = i;
                    longest = 2;
                }
            }
    
            for (int i = n - 3; i >= 0; i--) {
                for (int j = i + 2; j < n; j++) {
                    dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
                    if(dp[i][j] && longest < j - i + 1){
                        start = i;
                        longest = j - i + 1;
                    }
                }
            }
    
    
            return s.substring(start, start + longest);
        }
    }
  • 相关阅读:
    Philosophy is systematic reflective thinking on life.
    HashMap与HashTable的区别、HashMap与HashSet的关系
    android Intent机制详解
    Android Parcelable理解与使用(对象序列化)
    Java并发编程:volatile关键字解析
    JavaEE 对象的串行化(Serialization)
    pytorch学习
    numpy的一些用法
    约瑟夫问题
    双向链表及其操作
  • 原文地址:https://www.cnblogs.com/DarrenChan/p/11376563.html
Copyright © 2011-2022 走看看