算法刷题打卡049 | 动态规划17

这篇具有很好参考价值的文章主要介绍了算法刷题打卡049 | 动态规划17。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

动态规划终于要刷完了!虽然动规五部曲已经烂熟,也刷了有二三十题经典的动态规划题,但是自己实际做题时未必能用的很好,一方面是有些题目实在很难想到用动规解题,另一方面是即使想到动态规划,往往卡在状态的定义和状态转移上(更别说一些细节了,比如初始化),反复刷经典题目其实只是在学习方法论,关键还是得活学活用,毕竟做题时不会预先告诉你这时什么类型的题可以套什么思路~

LeetCode 647 回文子串

题目链接:647. 回文子串 - 力扣(Leetcode)

 一开始看题会如讲解所说的陷入一个误区,就是用编辑距离的方式定义dp数组,dp[i]和dp[i-1]之间不知道怎么构造状态转移。回文的性质使得解题需要打开思路,如果一个字符串中首尾字符相同,去掉首尾字符后的子串如果是回文的,那么整个字符串就是回文的。这里对于单个字符串也要使用二维的dp数组,dp[i][j]定义为s[i : j](左闭右闭区间)是否为回文串,遍历i和j就枚举了子串的首尾位置,又因为j要大于等于i(等于时为单个字符,也是回文的),遍历时需要将j初始化为i。

定义好dp数组后,状态转移上,s[i]和s[j]不相等,s[i : j]必然不能构成回文子串;如果s[i]==s[j],dp[i][j]的结果取决于dp[i+1][j-1](除去s[i]和s[j]之后的子串是否为回文子串),从而也决定了遍历顺序上,i 需要倒序遍历,j 则可以正序遍历。

class Solution {
public:
    int countSubstrings(string s) {
        int n = s.length();
        vector<vector<bool>> dp(n, vector<bool>(n, false));
        int result = 0;
        for(int i = n - 1; i >= 0; i--){
            for(int j = i; j < n; j++){
                if(s[i] == s[j]){
                    if(j - i <= 1){
                        dp[i][j] = true;
                        result++;
                    }
                    else if(dp[i+1][j-1]){
                        // 遍历顺序决定了i+1不会越界
                        dp[i][j] = true;
                        result++;
                    }
                }
                // else dp[i][j] = false;  初始化已经为false,可以不写
            }
        }
        return result;
    }
};

动态规划做多了,也没想过用双指针。双指针的时间复杂度也是O(n^2),但省去了dp数组的空间复杂度,主要方法就是以某一个或两个字符为中心点向左右遍历,判断能否构成回文(自己懒得写,贴上代码随想录的C++实现):

class Solution {
public:
    int countSubstrings(string s) {
        int result = 0;
        for (int i = 0; i < s.size(); i++) {
            result += extend(s, i, i, s.size()); // 以i为中心
            result += extend(s, i, i + 1, s.size()); // 以i和i+1为中心
        }
        return result;
    }
    int extend(const string& s, int i, int j, int n) {
        int res = 0;
        while (i >= 0 && j < n && s[i] == s[j]) {
            i--;
            j++;
            res++;
        }
        return res;
    }
};

LeetCode 516 最长回文子序列

题目链接:516. 最长回文子序列 - 力扣(Leetcode)

 相比于上一题,子序列不要求连续,定义区间s[i: j]之间的最长回文子序列的长度为dp[i][j],如果s[i]==s[j],dp[i][j] = dp[i-1][j-1]+2;如果s[i] != s[j],也就是不能可以只在s[i-1: j-1]的基础上在左边加上s[i],或者在右边考虑加上s[j],看是否能让回文子序列的长度增加,二者取最大即可。

遍历顺序和回文子串中的类似,由于dp数组含义不同,这里dp数组还要做额外的初始化,将dp[i][i]均初始化为1,因为在遍历过程中无法遍历到单个字符的情况:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.length();
        vector<vector<int>> dp(n, vector<int>(n));
        for(int i = 0; i < n; i++) dp[i][i] = 1;
        
        for(int i = n - 1; i >= 0; i--){
            for(int j = i + 1; j < n; j++){
                // j = i的情况已经初始化,j从i+1开始遍历
                if(s[i] == s[j]){
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                }
                else{
                    // 第一项:在右边加入s[j];第二项:在左边加入s[i];
                    dp[i][j] = max(dp[i + 1][j], dp[i][j-1]);
                }
            }
        }
        return dp[0][n-1];  // s[0 : n - 1]之间的最长回文子序列的长度(左闭右闭区间)

    }
};

这一题对于我来说不是那么好想,因为连续的限制更多,状态转移其实会更明确一些。文章来源地址https://www.toymoban.com/news/detail-414440.html

到了这里,关于算法刷题打卡049 | 动态规划17的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 力扣刷题-动态规划算法3:完全背包问题

    问题描述: 1)有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。 2) 每件物品都有无限个(也就是可以放入背包多次) (比0-1背包多出的条件) 3) 求解将哪些物品装入背包里物品价值总和最大。 求解步骤: 1)首先遍历物品,然

    2023年04月13日
    浏览(58)
  • 算法打卡day39|动态规划篇07| Leetcode 70. 爬楼梯(进阶版)、322. 零钱兑换、279.完全平方数

    Leetcode 70. 爬楼梯(进阶版) 题目: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬至多m (1 = m n)个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。 输入描述:输入共一行,包含两个正整数,分别表示n, m 输出描述:输出一个整数,

    2024年04月14日
    浏览(65)
  • OJ刷题---[算法课动态规划]走网格(C++完整代码)

    m行n列的网格,从左上角(1,1)出发,每一步只能向下或者向右,问共有多少种方法可以走到右下角(m,n); 输入参数 m n (1=m=10 1=n=10) 输出多少种走法 比如: 输入:2 3 输出:3 输入:5 5 输出:70 完整代码(C++): 结果: 注意:最后调用的时候,是调用sum(m,n),而不是sum(m+1

    2024年02月07日
    浏览(40)
  • 【算法|动态规划No.17】leetcode64. 最小路径和

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成长,共同进步。

    2024年02月07日
    浏览(49)
  • 【leetcode刷题之路】剑指Offer(4)——分治+排序算法+动态规划

    8 分治算法 8.1 【递归】剑指 Offer 07 - 重建二叉树 https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/   前序遍历是根左右,中序遍历是左根右,这也就意味着前序遍历的第一个节点是整棵树的根节点,顺着这个节点找到它在中序遍历中的位置,即为in_root,那么in_root左边的都在左子

    2024年02月11日
    浏览(59)
  • 【leetcode刷题之路】初级算法(2)——链表+树+排序和搜索+动态规划

    3.1 【链表】删除链表中的节点 https://leetcode.cn/problems/delete-node-in-a-linked-list/ 给出的就是要删除的那个节点,直接前后移动就行了。 3.2 【双指针】删除链表的倒数第 N 个结点 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/ 利用双指针left和right,首先让right遍历n个节点,再让两

    2024年02月10日
    浏览(51)
  • 算法刷题Day 38 动态规划理论基础+斐波那契数+爬楼梯

    动态规划的解题步骤: 确定 dp 数组(dp table)以及下标的含义 确定递推公式 dp 数组如何初始化 确定遍历顺序 举例推导 dp 数组 很基础

    2024年02月15日
    浏览(63)
  • 力扣算法刷题Day39|动态规划:不同路径 I&II

    力扣题目:#62.不同路径 刷题时长:参考题解后10min 解题方法:动规 复杂度分析 时间O(m*n) 空间O(m*n) 问题总结 初始化二维数组的python语法:i 对应 m,j 对应n 二维遍历顺序,从上到下从左到右通过两层for循环实现,其中startindex应为1 本题收获 动规思路 确定dp数组及下标的含义

    2024年02月12日
    浏览(52)
  • 【算法日志】动态规划刷题:01背包问题,多重背包问题(day37,day38)

    目录 前言 目标和(01背包) 一和零(01背包) 零钱兑换(多重背包) 排列总和(多重背包) 这两天都是背包问题,其中的01背包的一些应用问题需要一定的数学建模能力,需要i将实际问题简化成我们熟悉的背包问题;而这两天的多重背包问题还算比较基础,但也要我明白了

    2024年02月11日
    浏览(56)
  • 力扣算法刷题Day42|动态规划:01背包问题 分割等和子集

    力扣题目:01背包问题(二维数组) 刷题时长:参考题解 解题方法:动态规划 + 二维dp数组 复杂度分析 时间 空间 问题总结 理解递推公式困难 本题收获 动规思路:两层for循环,第一层i遍历物品,第二层j枚举背包容量以内所有值 确定dp数组及下标的含义:dp[i][j] 表示从下标

    2024年02月13日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包