93、动态规划-最长回文子串

思路

首先从暴力递归开始,回文首尾指针相向运动肯定想等。就是回文,代码如下:

java 复制代码
public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        return longestPalindromeHelper(s, 0, s.length() - 1);
    }

  // 递归方法,用于寻找从left到right范围内的最长回文子串
    private String longestPalindromeHelper(String s, int left, int right) {
        if (left == right) {
            return s.substring(left, right + 1); // 如果左右指针相等,说明是单个字符,单个字符本身是回文
        }
        // 如果当前字符串是回文,直接返回这个子串
        if (isPalindrome(s, left, right)) {
            return s.substring(left, right + 1);
        }

        // 不是回文时,尝试两种情况:忽略左边字符或忽略右边字符
        String leftPalindrome = longestPalindromeHelper(s, left + 1, right);  // 忽略左边字符
        String rightPalindrome = longestPalindromeHelper(s, left, right - 1); // 忽略右边字符

        // 比较这两种情况,返回更长的那个回文子串
        return leftPalindrome.length() > rightPalindrome.length() ? leftPalindrome : rightPalindrome;
    }

    // 辅助方法,用于检查给定字符串s从left到right的部分是否是回文
    private boolean isPalindrome(String s, int left, int right) {
        while (left < right) {  // 双指针法检查是否回文
            if (s.charAt(left) != s.charAt(right)) {
                return false; // 一旦发现不对称,立即返回false
            }
            left++;  // 移动左指针
            right--; // 移动右指针
        }
        return true; // 所有字符均对称,是回文
    }

递归面临很多重复计算,这个时候可以使用动态规划

动态规划的思路:

  1. 状态定义 :定义 dp[i][j] 为布尔值,表示字符串从索引 i 到索引 j 的子串是否为回文。
  2. 初始化 :单个字符总是回文,所以对于所有 idp[i][i]true
  3. 状态转移方程 :如果 s[i]s[j] 相等,并且内部的子串也是回文(即 dp[i+1][j-1]true 或者 ij 之间的距离小于等于2),那么 dp[i][j] 也应该是 true
  4. 从底向上填表 :由于每个状态依赖于左下方的状态(即 dp[i+1][j-1]),我们需要从下向上和从左到右填充这个表。
java 复制代码
 public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        String longest = "";

        // 填充动态规划表
        for (int len = 1; len <= n; len++) { // len 是当前子串的长度
            for (int start = 0; start < n; start++) {
                int end = start + len - 1;
                if (end >= n) { // 确保不越界
                    break;
                }
                // 设置dp[start][end]的值
                dp[start][end] = (s.charAt(start) == s.charAt(end)) && (len <= 2 || dp[start + 1][end - 1]);

                // 如果当前子串是回文,检查它是否是最长的回文
                if (dp[start][end] && len > longest.length()) {
                    longest = s.substring(start, end + 1);
                }
            }
        }
        return longest;
    }
相关推荐
Haohao+++6 小时前
Stable Diffusion原理解析
人工智能·深度学习·算法
ideaout技术团队9 小时前
leetcode学习笔记2:多数元素(摩尔投票算法)
学习·算法·leetcode
代码充电宝9 小时前
LeetCode 算法题【简单】283. 移动零
java·算法·leetcode·职场和发展
不枯石12 小时前
Matlab通过GUI实现点云的均值滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab·均值算法
不枯石12 小时前
Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
白水先森14 小时前
C语言作用域与数组详解
java·数据结构·算法
想唱rap14 小时前
直接选择排序、堆排序、冒泡排序
c语言·数据结构·笔记·算法·新浪微博
老葱头蒸鸡15 小时前
(27)APS.NET Core8.0 堆栈原理通俗理解
算法
视睿15 小时前
【C++练习】06.输出100以内的所有素数
开发语言·c++·算法·机器人·无人机
柠檬071116 小时前
matlab cell 数据转换及记录
算法