Leetcode(5)——最长回文子串(动态规划法)

       关于Leetcode的刷题方法,在网上看了很多,每个人都有着不同的见解。作为Leetcode小白,我还是决定用最原始的方法进行刷题,即把每一题的思路都记录下来,虽然比较耗时间,但是个人感觉这样子的方法会让我对题目有更深入的了解。希望能在该专栏中记录下刷题过程中遇到的大大小小的问题🍊。

题目描述

在这里插入图片描述


解题思路

  • 本题在leetcode的题解上面看到了非常多的方法,但我感觉这题跟之前看到的动态规划的题目挺相似,就借着这题来熟悉下动态规划的用法。
  • 既然是动态规划,那么就要从题目入手。我们需要寻找的是回文字符串,那就从回文字符串的性质入手。
  • 对于一个回文字符串,如果它的长度是1,则必定是回文字符串。
  • 如果它的长度是2,则当两个字符相同的时候才为回文字符串。
  • 如果它的长度大于2,假设它是回文字符串的话,必须满足下面两个性质:
    1.首尾两个字符必然相等。
    2.去除掉首尾两个字符之后仍然是回文字符串。
    • 比如字符串“abcba”的长度为5,且首尾两个字符相等,即满足回文字符串的第一条性质。

    • 同时去除掉首尾两个字符后为”bcb“,其中首尾两个字符都是b,即满足回文字符串的第一条性质。

    • 同时去除掉首尾的两个”b“之后剩下的是”c“,由于长度为1,必定是回文字符串

    • 综上所述,”abcba“是回文字符串

    • 这两个性质可以反过来思考,即当字符串长度大于2的时候,若首尾两个字符不相等,则必然不是回文字符串。

动态规划方程构造

  • 上面我们把一个字符串是否为回文字符串的三种情况都列出来了,下面就是思考如何构造动态规划方程。
  • 由于动态规划是一个自底向上的思想,具体一些实际上就是填充一个二维数组,那么这个自底向上的”底“体现出来就是先填充二维数组的哪个位置。而取决于这个”底“的关键因素就是我们上面提到的第三种情况,字符串长度大于2:
    • 上面提到当我们判断一个长度大于2的字符串的时候,如果首尾两字符不相等,那我们可以直接排除它,即不可能为回文字符串。
    • 那么如果首尾两字符相等呢?此时就要判断除去首尾两字符后的字符串是否为回文字符串,这个过程是一个自顶向下的过程,即不断地缩小我们的判断范围。
    • 而动态规划的根本核心就是:除去首尾两字符之后的字符串,一定已经在先前判断过了,即一步到位,不用再重复去除首尾两个字符递归去求解
    • 比如我们的字符串”abcba“,我们用二维数组P[ i ][ j ]来判断i到j区间(左右都是闭区间)的字符串是否为回文字符串,比如i=0,j=4,此时s[ i ] = s[ j ] = a,因此我们需要去除掉首尾两字符,即缩小判断的范围,具体就是让i + 1,j - 1,判断P【i+1】【j-1】是否为回文字符串。
    • 整道题目的核心,就是我们要确保这个P【i+1】【j-1】一定是在计算P【i】【j】之前就已经计算过了。
      要达到这个目的,我们的二重循环遍历就需要先遍历i比较大的,j比较小的,这样子当我们遍历 i 的时候,才能保证 i+1 已经被遍历过了,遍历 j 的时候,才能保证 j-1 被遍历过了。

思路整理

在这里插入图片描述


题目代码

class Solution {
public:
	string longestPalindrome(string s) {
		string result;              //储存最终结果
		int len = s.length();       //获取字符串长度

        int **a = new int*[len];    //创建并初始化二维数组
        for(int i=0;i<len;i++){
            a[i] = new int[len];
            for(int j=0;j<len;j++){
                a[i][j] = 0;
            }
        }

        //分三种情况填充二维数组
		for (int i = len - 1; i >= 0; i--) {
			for (int j = i; j < len; j++) {
                //长度为1和长度为2的情况
				if (j - i == 0 || (j - i == 1 && s[i] == s[j])) {
					a[i][j] = 1;
				}
                
                //长度大于2的情况
				else if (j - i > 1 && s[i] == s[j] && a[i + 1][j - 1] == 1) {
                    a[i][j] = 1;
				}

				//更新最终结果result
				if (j - i + 1 > result.length() && a[i][j] == 1) {
					result = s.substr(i, j - i + 1);
				}
			}
		}
		return result;
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值