LeetCode: 516. 最长回文子序列(DP,思路清奇)

117 篇文章 0 订阅
48 篇文章 1 订阅

【问题描述】
给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。

示例 1:
输入:

“bbbab”
输出:

4
一个可能的最长回文子序列为 “bbbb”。

示例 2:
输入:

“cbbd”
输出:

2
一个可能的最长回文子序列为 “bb”。

【思路】
我一开始完全是按照最长递增子序列的思路来的,唯一的区别就是维护了一个start数组来存放每个回文序列的起始字符下标位置。因为根据回文序列的性质,最后一个字符一定要与第一个字符相等,如果相等就代表可以作为回文序列的一员嘛
于是写出了以下代码:

class Solution {
public:
    int dp[1005];           //dp[i]表示以i结尾的最长回文子序列的长度
    int start[1005];
    
    int longestPalindromeSubseq(string s) {
        int length = s.size();
        if(length == 0)                 //空串的坑
            return 0;
        //先赋初值
        for(int i = 0;i < length;i++)
        {
            dp[i] = 1;
            start[i] = i;
        }
        for(int i = 1;i < length;i++)
        {
            for(int k = 0;k < i;k++)
            {
                if(s[i] == s[start[k]])             //回文串性质:最后一个字符必须和开头的字符相同
                {
                    dp[i] = max(dp[i], dp[k] + 1);
                    start[i] = start[k];            //这句差点写掉
                }
            }
        }
        //最后扫描一遍dp数组,找出最大值
        int max_res = dp[0];
        for(int i = 1;i < length;i++)
        {
            max_res = max(max_res, dp[i]);
        }
        return max_res;
    }
};

然鹅,答案错误!发现是aabaa这种情况死活解决不了。。。

想了一会儿还是没啥思路,查查吧。发现竟然。。。根据回文子序列的性质,将原字符串s逆序一下得到字符串t, 然后求两者的最长公共子序列就可以了,我。。。。

不得不说,这个思路确实清奇,我没想到。以后回文序列的题可以考虑用这种思路,是个启发

Ac代码:

class Solution {
public:
    int dp[1001][1001];
    
    int longestPalindromeSubseq(string s) {
        if(s == "")
            return 0;
        int length = s.size();
        //反序
        string t = s;
        reverse(t.begin(), t.end());
        for(int j = 0;j < length;j++)
        {
            if(t[0] == s[j])
            {
                for(int k = j;k < length;k++)
                {
                    dp[0][k] =  1;
                    
                }
                break;
            }
        }
        for(int j = 0;j < length;j++)
        {
            if(s[0] == t[j])
            {
                for(int k = j;k < length;k++)
                {
                    dp[k][0] =  1;
                    
                }   
                break;
            }

        }
        for(int i = 1;i < length;i++)
        {
            for(int j = 1;j < length;j++)
            {
                if(t[i] == s[j])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
            }
        }
        /*
        for(int i = 0;i < length;i++)
        {
            for(int j = 0;j < length;j++)
            {
                cout << dp[i][j] << " ";
            }
            cout << endl;
        }*/
        return dp[length - 1][length - 1];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值