【力扣】从零开始的动态规划

news2024/12/24 9:07:35

【力扣】从零开始的动态规划

文章目录

  • 【力扣】从零开始的动态规划
    • 开头
    • 139. 单词拆分
      • 解题思路
    • 45. 跳跃游戏 II
      • 解题思路
    • 5. 最长回文子串
      • 解题思路
    • 1143. 最长公共子序列
      • 解题思路
    • 931. 下降路径最小和
      • 解题思路

开头

本力扣题解用5题来引出动态规划的解题步骤,用于本人进阶掌握动态规划,在刷题过程中写下的一些解题步骤与思路,供大家一起学习

139. 单词拆分

139. 单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s

**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

解题思路

状态表示: dp[i]表示字符串以0到i-1的字符串,能否组成字串

初始状态:dp[0]=true,没有字符串的情况肯定为true,如果这个为false,那么后面全部为false

状态转移方程:

​ 可以把一个字符串来看成两段,0~j-1j~i,前面一半可以看成dp[j],因为看下状态表示就知道了,dp[i]表示字符串以0到i-1的字符串, 带入j得dp[j]表示字符串以0到j-1的字符串。

​ 后一半直接在哈希表中找子串是否存在,找到了就是true,如果两个字串同时为true,那么dp[i]=true

​ 因为以0~i的字符串的分解的情况有很多种,只要其中一种为true,那么就是true,直接break

​ 所以动态转移方程为:

            if(dp[j] && set.contains(s.substring(j,i)))
            {
                dp[i]=true;
                break;
            }
import java.util.HashSet;
import java.util.Set;

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> set=new HashSet<>(wordDict);
        int n=s.length();
        boolean[] dp=new boolean[n+1];
        dp[0]=true;
        //从第i个字符结束的
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(dp[j] && set.contains(s.substring(j,i)))
                {
                    dp[i]=true;
                    break;
                }
            }
        }
        return dp[n];
    }
}

45. 跳跃游戏 II

45. 跳跃游戏 II

给定一个长度为 n0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i]
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

解题思路

状态表示: dp[i]表示从1开始跳到第i个数的最小次数

​ **初始状态:**第1个元素是起点,可以到达,其他所有结点默认无法到达,设置一个很大的初始值

状态转移方程:

​ 第i个数可以从前面任意一个跳跃距离大于两个结点距离的结点,及判断条件if(nums[j]>=i-j),在这些满足要求的结点中取最小值,方程为

dp[i]=min(dp[0],dp[1],dp[2]...dp[n-1])+1,写成循环结构,最终方程为:dp[i]=Math.min(dp[i],dp[j]+1);

import java.util.Arrays;

class Solution {
    public int jump(int[] nums) {
        int n=nums.length;
        int[] dp=new int[n];
        Arrays.fill(dp,Integer.MAX_VALUE);
        //状态表示:前跳到第i个的最小次数
        dp[0]=0;
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<i;j++)
            {
                int l=i-j;
                if(nums[j]>=l)
                {
                    dp[i]=Math.min(dp[i],dp[j]+1);
                }

            }
        }
        return dp[n-1];
    }
}

5. 最长回文子串

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

解题思路

状态表示: dp[i][j] 表示 i到j是否是一个回文串

​ **初始状态:**无

状态转移方程:

​ 想要知道dp[i][j]是否是一个回文子串,只需知道dp[i+1][j-1]是否是一个回文子串并且外层的字符相等即s[i]==s[j],那么dp[i][j]就是一个回文子串,还有一种特殊情况是:要判断的字符串只有两个字符时,不用再判断dp[i+1][j-1]是否是一个回文子串,只需判断这两个字符是否相等即可

​ **循环顺序:**想要知道循环顺序是从大到小,还是从小到大,我们要知道dp数组中哪个要先算出来 ,哪个后算出来,比如想要知道dp[i][j]是否是一个回文子串,就得先知道dp[i+1][j-1]是否也是一个回文子串,所以dp[i+1][j-1]要被先计算出来,分为两重循环来分析

​ 外重循环i+1比i要先知道,所以,i从大到小循环

​ 内重循环j-1比j要先知道,所以j从小到大循环

​ 又因为j一定要大于等于i,因为范围表示是i~j,所以j从i到n-1

            if(s.charAt(i)==s.charAt(j))
            {
                if(j-i<2 || dp[i+1][j-1] )
                    dp[i][j]=true;
            }
class Solution {
    public String longestPalindrome(String s) {
        int n=s.length();
        //状态表示:i到j是否是一个回文串
        boolean[][] dp=new boolean[n][n];

        //dp[i][j]=dp[i+1][j-1] && s.charAt(i)==s.charAt(j)
        String str="";
        for(int i=n-1;i>=0;i--)
        {
            for(int j=i;j<n;j++)
            {
                if(s.charAt(i)==s.charAt(j))
                {
                    if(j-i<2 || dp[i+1][j-1] )
                        dp[i][j]=true;
                }
                if(dp[i][j] && (j-i+1)>str.length())
                {
                    str=s.substring(i,j+1);
                }
            }
        }
        return str;
    }
}

1143. 最长公共子序列

1143. 最长公共子序列

给定两个字符串 text1text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace""abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

解题思路

状态表示:dp[i][j] 表示 text1[0:i-1]text2[0:j-1] 的最长公共子序列

**状态转移方程:**知道状态定义之后,我们开始写状态转移方程。

​ 当 text1[i - 1] == text2[j - 1] 时,说明两个子字符串的最后一位相等,所以最长公共子序列又增加了 1,所以 dp[i][j] = dp[i - 1][j - 1] + 1;举个例子,比如对于 ac 和 bc 而言,他们的最长公共子序列的长度等于 a 和 b 的最长公共子序列长度 0 + 1 = 1。
text1[i - 1] != text2[j - 1] 时,说明两个子字符串的最后一位不相等,那么此时的状态 dp[i][j] 应该是 dp[i - 1][j]dp[i][j - 1] 的最大值。举个例子,比如对于 ac和 bc 而言,他们的最长公共子序列的长度等于 ① ace 和 b 的最长公共子序列长度0 与 ② ac 和 bc 的最长公共子序列长度1 的最大值,即 1。

​ 所以状态转移方程为:当text[i-1]==text[j-1]时.dp[i][j]=dp[i-1][j-1]+1

​ 当text[i-1]!=text[j-1]时,dp[i][j]=max(dp[i−1][j],dp[i][j−1])

**初始值:**初始化就是要看当 i = 0 与 j = 0 时, dp[i][j] 应该取值为多少。

当 i = 0 时,dp[0][j] 表示的是 text1 中取空字符串 跟 text2 的最长公共子序列,结果肯定为 0.
当 j = 0 时,dp[i][0] 表示的是 text2 中取空字符串 跟 text1 的最长公共子序列,结果肯定为 0.
综上,当 i = 0 或者 j = 0 时,dp[i][j] 初始化为 0.

遍历方向与范围:由于 dp[i][j] 依赖与 dp[i - 1][j - 1] , dp[i - 1][j], dp[i][j - 1],所以 iii 和 jjj 的遍历顺序肯定是从小到大的。 另外,由于当 i 和 j 取值为 0 的时候,dp[i][j] = 0,而 dp 数组本身初始化就是为 0,所以,直接让 i 和 j 从 1 开始遍历。遍历的结束应该是字符串的长度为 len(text1) 和 len(text2)

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int n=text1.length();
        int m=text2.length();
        int[][] dp=new int[n+1][m+1];
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(text1.charAt(i-1)==text2.charAt(j-1))
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return dp[n][m];
    }
}

931. 下降路径最小和

931. 下降路径最小和

给你一个 n x n方形 整数数组 matrix ,请你找出并返回通过 matrix下降路径最小和

下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)(row + 1, col) 或者 (row + 1, col + 1)

示例 1:

img

输入:matrix = [[2,1,3],[6,5,4],[7,8,9]]
输出:13
解释:如图所示,为和最小的两条下降路径

解题思路

状态表示:dp[i][j]表示走到matrix[i][j]的最小下降和

**初始值:**第一行全是0,因为在原地(起点)

**状态转移方程:**到达dp[i][j]可以从上一层的相邻元素到达,取其中的最小值并加上一步的数量,即dp[i][j]=min(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+matrix[i][j],因为要判断边界条件,在最左边和最右边只能从上一层的两个到达。

​ 综上所诉,状态转移方程为:

if(j==0)
    dp[i][j]=Math.min(dp[i-1][j],dp[i-1][j+1])+matrix[i][j];
else if(j==m-1)
    dp[i][j]=Math.min(dp[i-1][j-1],dp[i-1][j])+matrix[i][j];
else
    dp[i][j]=Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i-1][j+1]))+matrix[i][j];

**答案:**根据题目要求,到达最后一行的最少下降和,再看状态表示:dp[i][j]表示走到matrix[i][j]的最小下降和,所以答案就在dp的最后一行中,取最后一行的最小值即是答案

class Solution {
    public int minFallingPathSum(int[][] matrix) {
        int n=matrix.length;
        int m=matrix[0].length;
        int[][] dp=new int[n][m];
        for(int j=0;j<m;j++)
        {
            dp[0][j]=matrix[0][j];
        }
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(j==0)
                    dp[i][j]=Math.min(dp[i-1][j],dp[i-1][j+1])+matrix[i][j];
                else if(j==m-1)
                    dp[i][j]=Math.min(dp[i-1][j-1],dp[i-1][j])+matrix[i][j];
                else
                    dp[i][j]=Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i-1][j+1]))+matrix[i][j];
            }
        }
        int min=Integer.MAX_VALUE;
        for(int j=0;j<m;j++)
        {
            min=Math.min(min,dp[n-1][j]);
        }
        return min;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1221623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

各机构如何加强网络渗透、“渗透”防御

数据渗透&#xff0c;例如黑客攻击和“渗透”&#xff0c;或未经授权的信息传输。 联邦调查局、国家安全局以及网络安全和基础设施安全局最近的联合报告证明&#xff0c;网络安全仍然是当今国防部门面临的两个最大的网络威胁。 所谓的零日攻击尤其有害&#xff0c;因为组织在…

基于SSM的智能仓储系统研究与设计

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

C语言变量与常量

跟着肯哥&#xff08;不是我&#xff09;学C语言的变量和常量、跨文件访问、栈空间 栈空间还不清楚&#xff0c;期待明天的课程内容 C变量 变量&#xff08;Variable&#xff09;是用于存储和表示数据值的名称。 主要包括四个环节&#xff1a;定义、初始化、声明、使用 在我刚…

gorm的简单操作

1. 什么是orm ORM全称是&#xff1a;Object Relational Mapping(对象关系映射)&#xff0c;其主要作用是在编程中&#xff0c;把面向对象的概念跟数据库中表的概念对应起来。举例来说就是&#xff0c;我定义一个对象&#xff0c;那就对应着一张表&#xff0c;这个对象的实例&a…

LabVIEW编程开发NI-USRP

LabVIEW编程开发NI-USRP 可编程性是SDR的关键特性&#xff0c;它使人们能够将无线电外围设备转换为先进的无线系统。USRP是市场上最开放、最通用的SDR&#xff0c;可帮助工程师在主机和FPGA上使用各种软件开发工具构建系统。 有多种选项可用于对基于SDR的系统的主机进行编程。…

wpf devexpress Property Gird管理集合属性

Property Grid允许你添加&#xff0c;浏览和编辑集合属性

【2022改良版】学法减分助手PRO小程序源码

【2022改良版】学法减分助手PRO小程序源码 &#xff0c;交管推出个学法减分&#xff0c;每个驾驶员可以把被扣的6分&#xff0c;以看视频答题的形式学习回来&#xff0c;然后答题这个一共二十道题每道题60秒&#xff0c; 有好多人不会&#xff0c;用咱们的小程序就可以模拟练习…

鸿蒙开发|鸿蒙系统项目开发前的准备工作

文章目录 鸿蒙项目开发的基本流程介绍鸿蒙项目开发和其他项目有什么不同成为华为开发者-注册和实名认证1.登录官方网站 鸿蒙项目开发的基本流程介绍 直接上图&#xff0c;简单易懂&#xff01; 整个项目的开发通过4个模块进行&#xff1a;开发准备、开发应用、运行调试测试和发…

Typora for Mac:打造全新文本编辑体验

Typora for Mac是一款与众不同的文本编辑器&#xff0c;它不仅拥有直观易用的界面&#xff0c;还融合了Markdown语法和富文本编辑的功能&#xff0c;为用户带来了前所未有的写作和编辑体验。 一、简洁明了的界面设计 Typora for Mac的界面简洁明了&#xff0c;让用户可以专注…

解决更换NodeJs版本后npm -v返回空白

一、问题描述 win11电脑上输入cmd进入控制台&#xff0c;输入 node --version 有正常返回安装的nodejs的版本号 再输入 npm -v 返回空白。正常情况应该是要返回版本号。 二、问题背景 最近准备学习vue&#xff0c;在不久前已经安装了NodeJs和python。运行了好几个开源项…

2023年11月15号期中测验判断题(Java)

1-1 局部变量可以与成员变量重名。 正确答案&#xff1a;T 解释&#xff1a; 局部变量可以和成员变量重名&#xff0c;通常&#xff0c;为了区分局部变量和成员变量&#xff0c;会使用this关键字&#xff08;C称this指针&#xff0c;python是self关键字&#xff09;来特别声…

vim模式用法总结

0.前言 我们用gcc编译文件的时候&#xff0c;如果发生了下面的错误&#xff0c;那么如何用vim打开的时候就定位到&#xff1f; 我们可以知道&#xff0c;这是第6行出现了错误&#xff1b; 所以我们使用vim打开的时候多输入个这个&#xff0c;我们就可以快速定位了 vim test.c 6…

centos7 killall命令安装、使用

安装 在线安装命 输入下面命令 yum install psmisc -y Psmisc软件包包含三个帮助管理/proc目录的程序。 安装下列程序: fuser, killall,pstree和pstree.x11(到pstree的链接) fuser #显示使用指定文件或者文件系统的进程的PID。 killall #杀死某个名字的进程&#xff0c;它…

【咖啡品牌分析】Google Maps数据采集咖啡市场数据分析区域分析热度分布分析数据抓取瑞幸星巴克

引言 咖啡作为一种受欢迎的饮品&#xff0c;已经成为我们生活中不可或缺的一部分。随着国内外咖啡品牌的涌入&#xff0c;新加坡咖啡市场愈加多元化和竞争激烈。 本文对新加坡咖啡市场进行了全面的品牌门店数占比分析&#xff0c;聚焦于热门品牌的地理分布、投资价值等。通过…

react antd下拉选择框选项内容换行

下拉框选项字太多&#xff0c;默认样式是超出就省略号&#xff0c;需求要换行全展示&#xff0c;选完在选择框里还是要省略的 .less: .aaaDropdown {:global {.ant-select-dropdown-menu-item {white-space: pre-line !important;word-break: break-all !important;}} } html…

CTF-PWN-堆- 【off-by-one】

文章目录 堆的off-by-one利用思路Asis CTF 2016 b00ks libc 2.31IDA源码main输入名字creat函数dele函数edit函数print函数reeditor name函数 思路exp思路 堆的off-by-one off-by-one指的是单字节缓冲区溢出&#xff08;off-by-one 是可以基于各种缓冲区的&#xff0c;比如栈、…

Java编程中,异步操作流程中,最终一致性以及重试补偿的设计与实现

一、背景 微服务设计中&#xff0c;跨服务的调用&#xff0c;由于网络或程序故障等各种原因&#xff0c;经常会出现调用失败而需要重试。另外&#xff0c;在异步操作中&#xff0c;我们提供接口让外部服务回调。回调过程中&#xff0c;也可能出现故障。 这就要求我们主动向外…

Redis篇---第二篇

系列文章目录 文章目录 系列文章目录前言一、为什么 使用 Redis 而不是用 Memcache 呢?二、为什么 Redis 单线程模型效率也能那么高?三、说说 Redis 的线程模型前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这…

最新自动定位版本付费进群系统源码

更新内容&#xff1a; 1.在网站首页增加了付款轮播功能。 2.新增了城市定位功能&#xff0c;方便用户查找所在城市的相关信息。 3.对域名库及支付设置进行了更新和优化。 4.增加了一种图模板设置模式&#xff0c;简化了后台模板设置流程。 5.此外还进行了前后台的其他优化…

音频类型转换工具-可执行文件exe/dmg制作

朋友车载音乐需要MP3格式&#xff0c;想要个批量转换工具 准备工作 brew install ffmpeg --HEAD或者官网下载安装ffmpeg并配置环境conda install ffmpeg 或者pip install ffmpeg-python 音频类型转换程序.py文件 exe文件在windows下打包&#xff0c;dmg在macos下打包&#…