数据结构和算法-动态规划(3)-经典问题

动态规划常见问题

打家劫舍

题目

[力扣198] 198. 打家劫舍 - 力扣(LeetCode)

题目描述

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。偷窃到的最高金额 = 2 + 9 + 1 = 12

解决方案

image-20241025173303997
边界条件
  • 只有一间房子

    image-20241025173425916
    if(nums.length==1) return nums[0];
    
  • 有2间房子

    image-20241025173705041
    if (nums.length == 2)
    return Math.max(nums[0],nums[1]);
    
一般情况
  • 定义记忆化数组int[] , 记录每次偷窃成功的值。

    int[] dp = new int[nums.length];
    
  • 初始化dp(1间房子或两间房子)

    dp[0] = nums[0];
    dp[1] = Math.max(nums[0],nums[1]);
    
  • 其它情况

    • 当前盗取的第K个房间的结果与 前K-2 个有关
    • 如果不选择盗取当前K,则与K-1有关
    //状态转移方程
    dp[K] = max(dp[K-2] + nums[K], dp[K-1]);
    

    tips: 不能盗取相邻的房子

    image-20241025175059256

    for (int i = 2; i < nums.length; i++) {dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
    }
    

    提交模版

    class Solution {public int rob(int[] nums) {}
    }
    

    参考实现

    class Solution {public int rob(int[] nums) {// 定义dp数组,存储最优结果int[] dp = new int[nums.length];if (nums.length == 1) {return nums[0];}/** 边界条件: 只有两间房子*/dp[0] = nums[0];dp[1] = Math.max(nums[0], nums[1]);/** 状态转移方程*/for (int i = 2; i < nums.length; i++) {dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[dp.length - 1];}
    }
    

打家劫舍II

题目

[力扣213] 213. 打家劫舍 II - 力扣(LeetCode)

题目描述

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

示例 1:

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2, 因为他们是相邻的。

示例 2:

输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4

示例 3:

输入:nums = [1,2,3]
输出:3

解决方案

image-20241025175625102
边界条件
  • 只有一间房子

    image-20241025173425916
    if(nums.length==1) return nums[0];
    
  • 有2间房子

    image-20241025173705041
    if (nums.length == 2)
    return Math.max(nums[0],nums[1]);
    
一般条件

提交模版

参考实现

class Solution {public int rob(int[] nums) {if (nums.length == 1) {return nums[0];} else if (nums.length == 2) {return Math.max(nums[0], nums[1]);} else {int a = robRange(nums, 0, nums.length - 1);int b = robRange(nums, 1, nums.length);return Math.max(a, b);}}public int robRange(int[] nums, int start, int end) {int[] a =  Arrays.copyOfRange(nums,start, end);int pre = 0;int curr = 0;int tmp = 0;for(int i =0 ;  i< a.length; i++){tmp = curr;curr = Math.max(pre + a[i], curr);pre = tmp;}return curr;}
}

子串问题

问题

两组字符串 X=“ATCTGAT”, Y= “TGCATA”, 找出相同的子字符串,且顺序不变Z=“TCAT”, 长度4。

分析

检查X,Y较小的字符串看看它们的最长子串,分成两类最后一个字符相同,最后一个字符不同

如果其中一个字符串为空

如果X,Y中任意一个字符串为空,那么不存在最长子串问题

最长子串 = 0 ;    X,y的字符串为空
从较小的问题看-末尾不同
  • Y不变,看X的较小字符串"ATCTGA"

    X = “ATCTGAT” 是由X1=“ATCTGA” 和“T"构成,看看X1 和Y的最大子串。“TCTA”

    image-20241026075618029

  • X不变, 看Y的较小字符串"TGCATA"

    X=“ATCTGAT”, Y1=“TGCAT”,最大子串 “TCAT"

  • 最大相同子串

    假设X字符串当前的索引为 i;Y字符串的索引为j。

    最大长度 = max(X之前的最大字符串, Y之前的字符串)
    
末尾相同
image-20241026081203563

最长子串就是之前的最大子串+当前的相同字符

最大子串 = 之前的最大子串+1

解决方案

由分析可得,最大子串可以分为3中情况,使用int[][] dp数组记忆化步骤。

image-20241026082028017

package com.ffyc.dp;public class SubString {public static void main(String[] args) {String x = "ATCTGAT";String y = "TGCATA";int len1 = x.length();int len2 = y.length();int result = 0;if(len1==0|| len2 ==0) result = 0;int[][] dp = new int[len1][len2];for(int i=0; i< len1;i++){for(int j =0; j<len2;j++){if(i!=0 && j!=0){if(x.charAt(i) == y.charAt(j)){dp[i][j] = dp[i-1][j-1]+1;}else{dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);}}else{dp[i][j] = x.charAt(i)== y.charAt(j) ? 1 :0;}}}result = dp[len1-1][len2-1];System.out.println(result);}
}

买卖股票

买卖股票的最佳时机

题目

[力扣121] 121. 买卖股票的最佳时机 - 力扣(LeetCode)

描述

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0
解决方案
image-20241029083639199

有两个因素影响股票价格

  • 当天不卖,前一天的股票最大价格

    dp[d] = dp[d-1]; //d表示当天
    
  • 当天卖出某一天买入的最小价格,比如上周五买最低,本周二卖

    dp[d] = price[d]- min(dp[从开始--当天的最小值]);
    

动态转移方程

dp[i] = max(dp[i-1],  price[i]-min(dp[从开始--当天的最小值]));
提交模版
class Solution {public int maxProfit(int[] prices) {}
}
参考实现
class Solution {public int maxProfit(int[] prices) {int n = prices.length;if (n < 2)return 0;int[] dp = new int[n];int min = prices[0];for(int i=1; i < n;i++){dp[i] = Math.max(dp[i-1], prices[i]-min);min = Math.min(min, prices[i]);}return dp[n-1];}
}

买卖股票的最佳时机II

问题

[力扣122]122. 买卖股票的最佳时机 II - 力扣(LeetCode)

问题描述

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3。
最大总利润为 4 + 3 = 7

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。
最大总利润为 4

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0
解决方案

当天i, 有两种最大股票利润的状态,

  • 持有此股票的最大利润
  • 不持有此股票的最大利润

用二维数组创建记录数组: dp[天][是否持有股票] —0:不持有股票, 1:持有股票

tips: 可以当天买入当天卖出

  • 当天不持有

    • 前一天卖出,不持有

      dp[i-1][0]
      
    • 前一天买入,当天卖出,不持有,今天就可以盈利

      dp[i-1][1]+prices[i];
      
  • 当天持有

    • 前一天买入

      dp[i-1][1];
      
    • 前一天没有,当天买入,减去今天花费的成本

    dp[i-1][0]-price[i];
    
参考实现
class Solution {public int maxProfit(int[] prices) {int n = prices.length;if(n < 2) return 0;int[][] dp = new  int[n][2];dp[0][1] = 0- prices[0]; //当天成为买入成本for(int i=1; i<n;i++){dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]+prices[i]);dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]-prices[i]);}return dp[n-1][0];}
}

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

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

相关文章

深入理解Redis的四种模式

Redis是一个内存数据存储系统&#xff0c;支持多种不同的部署模式。以下是Redis的四种主要部署模式。 1、单机模式 单机模式是最简单的部署模式&#xff0c;Redis将数据存储在单个节点上。这个节点包括一个Redis进程和一个持久化存储。单机模式非常适合小型应用程序或者开发和…

Flutter实战短视频课程

1、课程导学 一套代研运行多蜡 体州一致&#xff0c;目胜能优昇 未来大趋势 不改交原生项目的基础上&#xff0c;扩展Flutter能力 Flutter原生灵话切涣 0入侵 最简单、最通用 最新Flutter 3,x新特性讲解 大量flutter官方组件和api学习 最常用的第三方库使用及原理解析 自研组…

消息队列-Rabbitmq(消息发送,消息接收)

将来我们开发业务功能的时候&#xff0c;肯定不会在控制台收发消息&#xff0c;而是应该基于编程的方式。由于RabbitMQ采用了AMQP协议&#xff0c;因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息&#xff0c;都可以与RabbitMQ交互。并且RabbitMQ官方也提供了各种不…

QT相机连接与拍照

先看效果 编辑:已添加虚拟键盘辅助输入,添加二维码识别,用的QZxing 初始化 auto mainLayout = new QHBoxLayout(this);m_viewfinder = new QCameraViewfinder(this);m_viewfinder->setStyleSheet("border-radius: 20px;background-color:rgb(43,48,70)");mainL…

ubuntu openmpi安装(超简单)

openmpi安装 apt update apt install openmpi-bin openmpi-common libopenmpi-dev安装到此完毕 测试一下&#xff0c;success !

【C++】string 类深度解析:探秘字符串操作的核心

快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 目录 &#x1f4af;前言 &#x1f4af;为什么要学习 string 类 &#xff08;一&#xff09;简化操作 &#xff08;二&#xff09;确保安全 &#xff08;三…

【EndNote版】如何在Word中引用文献

1、在Word中&#xff0c;鼠标光标放在所需插入文献的位置 2、点击选项卡中的“EndNote X9”&#xff0c;直接在EndNote中选中对应的文献 3、选中文献&#xff0c;点击工具栏中的“引用” 4、最后就可在Word中看到所插入的文献

[面试题]ES6 Javascript

ES6 箭头函数和普通函数有什么区别? 1)定义方式:箭头函数使用箭头(>)语法&#xff0c;省略了 function 关键字。 2)参数处理:如果只有一个参数&#xff0c;箭头函数可以省略括号。 3)函数体:如果函数体只有一条语句&#xff0c;箭头函数可以省略花括号和 return 关键字 4)…

Leetcode 二叉树中的最大路径和

算法思想 这道题要求在一棵二叉树中找到路径和最大的路径。路径可以从树中任意一个节点开始&#xff0c;到任意一个节点结束&#xff0c;但路径上的节点必须是连续的。 算法使用递归的方式来遍历树中的每个节点&#xff0c;并在遍历过程中计算包含当前节点的最大路径和。具体…

计算机视觉实验一:图像基础处理

1. 图像的直方图均衡 1.1 实验目的与要求 (1)理解直方图均衡的原理与作用; (2)掌握统计图像直方图的方法; (3)掌握图像直方图均衡的方法。 1.2 实验原理及知识点 直方图均衡化是通过灰度变换将一幅图象转换为另一幅均衡直方图&#xff0c;即在每个灰度级上都具有相同的象素…

计算结构力学:多自由度振动系统

本文以笔记的形式记录计算结构力学的若干基础知识。 注1&#xff1a;限于研究水平&#xff0c;分析难免不当&#xff0c;欢迎批评指正。 注2&#xff1a;文章内容会不定期更新。 预修1&#xff1a;线性代数 1. 标准特征值 复矩阵Schur分解&#xff1a;对于复矩阵&#xff0c…

Linux基础环境搭建(CentOS7)- 安装Scala和Spark

#Linux基础环境搭建&#xff08;CentOS7&#xff09;- 安装Scala和Spark Linux基础环境搭建&#xff08;CentOS7&#xff09;- 安装Scala和Spark 大家注意以下的环境搭建版本号&#xff0c;如果版本不匹配有可能出现问题&#xff01;&#xff08;spark不要下2.4版本的 会报错…

Vue3使用AntV | X6绘制流程图:开箱即用

x6官方地址X6图编辑引擎 | AntV 官方文档仔细地介绍了很多丰富的功能,这里的demo可以满足基本的使用,具体拓展还需要仔细看文档内容 先上效果图 1、安装 通过 npm 或 yarn 命令安装 X6。 # npm npm install @antv/x6 --save# yarn yarn add @antv/x6 初始化画布 <di…

安装使用docker harbor并推送镜像到仓库

1.概要 通过上一章节的讲解&#xff0c;我们基本了解了docker的操作命令&#xff0c;在文章的最后我们成功的推送一个镜像到DockerHub的镜像仓库。从流程上说&#xff0c;操作过程可以说很完美&#xff0c;但是整个推送过程消耗的时间太长&#xff0c;我们消耗了大量时间在访问…

HTML练习题:彼岸的花(web)

展示效果: 代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>彼岸の花</title><style…

thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql

最近接了一个陪玩小程序&#xff0c;其中有一个实时聊天的项目&#xff0c;需要搭建Websocke服务&#xff0c;通过多方考虑选择了通过GatewayWorker框架&#xff08;基于Workerman&#xff09;,将代码提取了出来&#xff0c;用到的框架封装到了vendor目录下&#xff0c;完整前后…

【计算机网络 - 基础问题】每日 3 题(五十八)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

C++ 二叉树进阶:相关习题解析

目录 1. 二叉树创建字符串。 2. 二叉树的分层遍历1 3. 二叉树的分层遍历2 4. 二叉树的最近公共祖先 5. 将二叉搜索树转换为排序的双向链表 6. 从前序与中序遍历序列构造二叉树 7. 从中序与后序遍历序列构造二叉树 8. 二叉树的前序遍历&#xff0c;非递归迭代实现 9.…

云舟观测:基于eBPF监控主机的TCP网络连接

1 背景 机器网络监控信息在日常问题排查中扮演着至关重要的角色&#xff0c;是不可或缺的工具。通过对网络流量的深入分析&#xff0c;我们不仅能有效评估网络性能&#xff0c;还能迅速识别异常行为&#xff0c;例如流量突然激增、未知的数据传输等&#xff0c;这些对于保障网络…

【IC每日一题】

IC每日一题 1&#xff1a;锁存器(latch)、触发器(flip-flop)、寄存器的概念及区别1.1 概念1.2 锁存器的危害1.3 如何避免产生锁存器 2 手撕题&#xff1a;边沿检测2.1 边沿检测(上升沿、下降沿、双边沿)2.1.1 波形图2.1.2 算法步骤2.1.3 代码 2.2 序列模三检测器2.2.1 描述2.2.…