首页 > 其他分享 >【每日一题】LeetCode - 最长回文子串

【每日一题】LeetCode - 最长回文子串

时间:2024-10-24 22:16:37浏览次数:10  
标签:子串 字符 int res 复杂度 LeetCode dp 回文

在字符串相关的算法题中,寻找最长回文子串是一个经典且富有挑战性的题目。本篇将详细分析并推导两种有效的解决方案:动态规划法和中心扩展法。

题目描述

给定一个字符串 s,我们需要找到 s 中最长的回文子串。回文是指正着读和反着读都相同的字符串。例如,输入 "babad" 时,输出可以是 "bab" 或者 "aba";输入 "cbbd" 时,输出为 "bb"

解题思路

方法一:动态规划

如果你不了解什么是动态规划,或者时空复杂度,请参考以下内容:

1. 定义状态: 我们使用一个二维布尔数组 dp,其中 dp[i][j] 表示字符串 s 从索引 ij 的子串是否是回文。

2. 状态转移方程:

s[i] == s[j]

且:j - i <= 1(即当子串长度为1时),则 dp[i][j] = true,因为此时其只有1个或两个字母,且字母相同,构成回文。

  • dp[i + 1][j - 1] == true(即如果去掉首尾字符的子串也是回文,因为你观察一个回文字符会发现,如果一个字符是回文那么当你去除其首尾仍然是回文,这样我们按照动态规划的思想,对之前的计算结果进行计算,之后避免重复计算就可以减少时间复杂度),则 dp[i][j] = true

3. 其他条件:

  • 所有单个字符的子串都是回文,因此 dp[i][i] = true
  • 两个相同字符组成的子串也是回文,即 dp[i][i+1] = (s[i] == s[i+1])

4. 实现代码:

class Solution {
public:
    string longestPalindrome(string s) {
        vector<vector<bool>> dp(s.size(), vector<bool>(s.size(), false));
        int result = 0;
        string str;

        for (int i = s.length() - 1; i >= 0; --i) {
            for (int k = i; k < s.length(); ++k) {
                if (s[i] == s[k] && (k - i <= 1 || dp[i + 1][k - 1])) {
                    dp[i][k] = true;
                    if (k - i >= result) {
                        result = k - i;
                        str = s.substr(i, k - i + 1);
                    }
                }
            }
        }
        return str;
    }
};

5. 时间复杂度: O(n²),空间复杂度为 O(n²)。

方法二:中心扩展法

1. 原理: 每个回文可以视为围绕中心展开的。我们可以考虑两种情况:

  • 以单个字符为中心(奇数长度回文,从单个字符开始左右定义两个指针,每次向外扩展,直到达到left == 0 || right == s.size() - 1边界,然后记录长度)。
  • 以两个相同字符为中心(偶数长度回文,这种情况比较适用与两个相同字母在一起,因为此时她们就构成回文了,如果只使用单个字符做为中心,那么--left != --right是绝对成立的)。

2. 扩展过程: 从每个中心开始,逐步向外扩展,比较左右字符是否相等,直到不能再扩展为止。

3. 实现代码:

class Solution {
public:
    string longestPalindrome(string s) {
        string res;
        for (int i = 0; i < s.length(); ++i) {
            int r1 = maxLength(s, i, i); // 奇数长度回文
            int r2 = maxLength(s, i, i + 1); // 偶数长度回文
            res = res.length() >= r1 * 2 - 1 ? res : s.substr(i - r1 + 1, r1 * 2 - 1);
            res = res.length() >= r2 * 2 ? res : s.substr(i - r2 + 1, r2 * 2);
        }
        return res;
    }

    int maxLength(string s, int left, int right) {
        int r = 0;
        while (left >= 0 && right < s.length() && s[left] == s[right]) {
            left--;
            right++;
            r++;
        }
        return r;
    }
};

4. 比较扩展长度: 在拿到最多扩展之后,我们就可以先判断字符长度是否比现有的最长回文长度大,若大,则根据单字符回文和双字符回文裁剪出字符串

4. 时间复杂度: O(n²),空间复杂度为 O(1)。

结果对比

动态规划方式

在这里插入图片描述

中心拓展方式

在这里插入图片描述

标签:子串,字符,int,res,复杂度,LeetCode,dp,回文
From: https://blog.csdn.net/qq_37945670/article/details/143161063

相关文章

  • 【leetcode-面试经典 150 题】-4.删除有序数组中的重复项 II
    题目:给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用O(1)额外空间的条件下完成。示例1:输入:nums=[1,1,1,2,2,3]输出:5,nums=......
  • 【leetcode-面试经典 150 题】-1.合并两个有序数组
    题目:给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 ......
  • LeetCode常用算法模板
    代码模板  1、DFS:适用于树和图的遍历、组合问题。2、BFS:适用于树和图的层次遍历、最短路径问题。3、二分查找:适用于有序数组的搜索问题。4、动态规划:适用于最优化问题、序列问题。5、贪心算法:适用于局部最优问题、调度问题。6、回溯算法:适用于组合、排列、子集问题。......
  • Leetcode每日一题:3175. 找到连续赢 K 场比赛的第一位玩家
    题意为给定一个数组,数组头两数比大小,大的放队首,小的放队尾,找到能够连续赢K次的数的编号。思路:如果一轮比较完了,没有赢K次的,那答案就是数组最大值。利用双指针,模拟一轮比较,计算每个数的胜利次数,注意,若起点不是0的话,意味着他和之前的数比较是胜出的,所以初始为1,否则初始为0;1clas......
  • [LeetCode] 951. Flip Equivalent Binary Trees
    ForabinarytreeT,wecandefineaflipoperationasfollows:chooseanynode,andswaptheleftandrightchildsubtrees.AbinarytreeXisflipequivalenttoabinarytreeYifandonlyifwecanmakeXequaltoYaftersomenumberofflipoperations......
  • 代码随想录算法训练营第九天|leetcode151.翻转字符串里的单词、卡码网55.右旋字符串
    1leetcode151.翻转字符串里的单词题目链接:151.反转字符串中的单词-力扣(LeetCode)文章链接:代码随想录视频链接:字符串复杂操作拿捏了!|LeetCode:151.翻转字符串里的单词_哔哩哔哩_bilibili自己的思路:直接将空格去掉,然后分割字符串为列表,在列表中进行翻转,不在字符串内部操作,......
  • leetcode-1661-每台机器的平均运行时间
    链接:1661.每台机器的进程平均运行时间-力扣(LeetCode)前提条件:表: Activity+----------------+---------+|ColumnName|Type|+----------------+---------+|machine_id|int||process_id|int||activity_type|enum||timest......
  • c++ 构成整天的下标对数目 leetcode
    目录一、leetcode3184.构成 整天 的下标对数目I1.问题描述 2.方法:暴力穷举二、leetcode3185.构成 整天 的下标对数目II1.问题描述2.方法:哈希表一、leetcode3184.构成 整天 的下标对数目I1.问题描述给你一个整数数组 hours,表示以 小时 为单位的时间,返......
  • leetcode-197-上升的温度
    链接:197.上升的温度-力扣(LeetCode)前提条件:表: Weather+---------------+---------+|ColumnName|Type|+---------------+---------+|id|int||recordDate|date||temperature|int|+---------------+---------+id是......
  • leetcode刷题-1581. 进店却未进行过交易的顾客
    链接:1581.进店却未进行过交易的顾客-力扣(LeetCode)前提条件:表:Visits+-------------+---------+|ColumnName|Type|+-------------+---------+|visit_id|int||customer_id|int|+-------------+---------+visit_id是该表中具有唯一值的列。......