letcode-动态规划解最长回文子串(消去二维数组)

动态规划解最长回文子串

题目

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

示例 3:

输入:s = "a"
输出:"a"

示例 4:

输入:s = "ac"
输出:"a"

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring

得到最长回文子串前,需要得到次最长子串。

例如字符串:cbbaabb ,它的最长回文子串为:bbaabb,得到该结果需要逐步确认: aa、baab 是回文,最终结论,bbaabb是回文子串。

类似此类需要依赖子问题结论的,求解都可以使用动态规划。

解题思路

有字符串:vxajkbbkja ,肉眼可判断最大回文为:ajkbbkja
如下图所示:我们只需要以中轴为起点,以途中红色箭头方向依次判断相等性,取到最长的即可。
(坐下部分对称,可以不必比较)

设横向为X, 纵向为Y,两个方向都从 字符v开始,字符a结束。延对称轴方向访问。
在这里插入图片描述

遍历如图红色箭头指向路径,如下每行对应一条红色箭头。
{0,0}
{1,0}
{1,1}{2,0}
{2,1}
{2,2}{3,1}
{3,2}
{3,3}{4,2}
{4,3}
{4,4}{5,3}
{5,4}
{5,5}{6,4}
{6,5}{7,4}{8,3}{9,2}
{6,6}{7,5}
{7,6}
{7,7}{8,6}
{8,7}
{8,8}{9,7}
{9,8}
{9,9}

最终得到相等的有点:{6,5}{7,4}{8,3}{9,2}
把它延对称轴映射:就可以得到最终的回文子串。

最终代码

我没有使用二维数组,所以节约了不少内存空间,由于增加了对特殊情况的判断,所以代码不是很简洁:

在这里插入图片描述


class Solution {
    

    public String longestPalindrome(String s) {
        char[] sArr = s.toCharArray();
        /** 记录当前步、最长步的起始位置和长度 */
        int maxLetf = 0, maxLen = 0, curLeft = 0, curLen = 0;
        /** 记录当前步、最长步的起点是否在对称轴上,如果在对称轴上,回文长度为奇数,否则回文长度为偶数 */
        boolean turnFlag = true, maxFlag = true;
        /** returnValue 记录回溯的位置,可以认为它是对横坐标 i 值的缓存,
        结合上一节,每条红线访问结束都需要回溯横坐标。  */
        int returnValue = 0;
        for(int i = 0; i < sArr.length;){
            int j = (turnFlag) ? i : i - 1;
            for(; j >= 0 && i < sArr.length; j--,i++){
                if (sArr[i] == sArr[j]) curLen++; 
                else break;
            }
            /** 起点不在对称轴上,把最终长度加1 */
            if (curLen != 0 && !turnFlag) curLen++;

            /** 当起点在对称轴上的时候,最大步长相等即记录为最长 */
            if (curLen > maxLen || (curLen == maxLen && turnFlag)){
                maxLen = curLen;
                maxLetf = curLeft;
                maxFlag = turnFlag;
            }
            /** 因为依次访问,所以起点间次在或不在对称轴上 */
            turnFlag = !turnFlag;
            if (turnFlag) i = returnValue;
            else i = ++returnValue;/** 前一次迭代不在对称轴上,下一次迭代起点在对称轴上,横坐标加1 */
            curLeft = i;/** 重置迭代起点 */
            curLen = 0;/** 清空步长 */
        }
        maxLetf = maxLetf - (--maxLen);
        maxLen = maxFlag ?  (maxLetf + maxLen + maxLen + 1) : (maxLetf + maxLen + maxLen);
        return s.substring(maxLetf, maxLen);
    }

}

设字符串长度为N,如下公式表示需要对比的次数,可以很直观的得到结论,时间复杂度就是二维表格一半格数近似和。

  • 省略低次项和系数后:时间复杂度为:O(N^2)

  • 因为没有使用二维数据:空间复杂度随求解字符串长度线性变化,复杂度为:O(N)。

利用本题同样思路,可以解两个字符串的最大公共子串,异曲同工。

排在我前边的应该都是马拉车算法大佬了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值