当前位置: 首页 > news >正文

剑指Offer题目笔记27(动态规划单序列问题)

面试题89:

面试题89

问题:

​ 输入一个数组表示某条街道上的一排房屋内财产的数量。相邻两栋房屋不能同时被盗,问小偷能偷取到的最多财物。

解决方案一(带缓存的递归):

解决方案:
  1. 由于有报警系统,小偷不能同时偷相邻两栋房屋,故小偷在到达标号为i的房屋时他能偷取的财物的最大值,即f(i)=max(f(i-2)+nums[i],f(i-1))。
  2. 创建一个数组dp,它的第i个元素dp[i]用来保存f(i)的结果。如果f(i)之前已经计算出结果,那么只需要从数组dp中读取dp[i]的值,不用再重复计算。如果之前从来没有计算过,则根据状态转移方程递归计算。
源代码:
class Solution {public int rob(int[] nums) {int[] dp = new int[nums.length];//将dp数组的所有值赋值为-1Arrays.fill(dp,-1);dfs(nums,nums.length-1,dp);return dp[nums.length-1];}private void dfs(int[] nums,int len,int[] dp){if(len == 0){dp[len] = nums[0];}else if(len == 1){dp[len] = Math.max(nums[0],nums[1]);}else if(dp[len] < 0){dfs(nums,len-1,dp);dfs(nums,len-2,dp);dp[len] = Math.max(dp[len-1],dp[len-2] + nums[len]);}}
}

解决方案二:(空间复杂度为O(n)的迭代):

解决方案:

​ 由下到上,先求出f(0)和f(1)的值,再通过状态转移方程f(i) = Math,max(f(i-1),f(i-2) + nums[i])求出f(2)以此类推求得f(i)。

源代码:
class Solution {public int rob(int[] nums) {int len = nums.length;int[] dp = new int[len];dp[0] = nums[0];if(len >= 2){dp[1] = Math.max(nums[1],nums[0]);}for(int i = 2;i < len;i++){dp[i] = Math.max(dp[i-1],dp[i-2] + nums[i]);}return dp[len-1];}
}

解决方案三:(空间复杂度为O(1)的迭代):

解决方案:

​ 观察上述代码,就能发现计算“dp[i]”时只需要用到“dp[i-1]”和“dp[i-2]”这两个值,也就是说,只需要缓存两个值就足够了,并不需要一个长度为n的数组。

源代码:
class Solution {public int rob(int[] nums) {int len = nums.length;int[] dp = new int[2];dp[0] = nums[0];if(len >= 2){dp[1] = Math.max(nums[0],nums[1]);}for(int i = 2;i < len;i++){dp[i % 2] = Math.max(dp[(i-1) % 2],dp[(i-2) % 2 ] + nums[i]);}return dp[(len - 1) % 2];}
}

解决方案四:(使用两个状态转移方程):

解决方案:

​ 由于小偷到达标记为i的房屋是有两个选择,他进去偷东西和不进去偷东西,定义f(i)为不进去偷东西,g(i)为进去偷东西,因此f(i)= max(f(i-1),g(i-1)),g(i) = f(i-1) + nums[1]。这两个状态转移方程有隐含条件i必须大于0,不然i-1没有意义,因此f(0)= 0,g(0) = nums[0]。

源代码:
class Solution {public int rob(int[] nums) {int len = nums.length;int[][] dp = new int[2][2];//dp【0】为f(i)dp[0][0] = 0;//dp【1】为g(i)dp[1][0] = nums[0];for(int i = 1;i < len;i++){dp[0][i % 2] = Math.max(dp[0][(i - 1) % 2],dp[1][(i - 1) % 2]);dp[1][i % 2] = Math.max(dp[0][i % 2],dp[0][(i-1) % 2] + nums[i]);}return Math.max(dp[0][(len - 1) % 2],dp[1][(len - 1) % 2]);}
}

面试题90:

面试题90

问题:

​ 一条环形街道上有若干房屋,输入一个数组表示该条街道上的房屋内财产的数量,计算小偷在这条街道上最多能偷取到的财产数量。

解决方案:
  1. 如果小偷去偷标号为0的房屋,那么他就不能去偷标号为n-1的房屋;如果小偷去偷标号为n-1的房屋,那么他就不能去标号为0的房屋。
  2. 可以将这个问题分解成两个子问题:一个问题是求小偷从标号为0开始到标号为n-2结束的房屋内能偷得的最多财物数量,另一个问题是求小偷从标号为1开始到标号为n-1结束的房屋内能偷得的最多财物数量。
源代码:
class Solution {public int rob(int[] nums) {int len = nums.length;if(len == 0){return 0;}if(len == 1){return nums[0];}//0~n-2int result1 = dfs(nums,0,len-2);//1~n-1int result2 = dfs(nums,1,len-1);return Math.max(result1,result2);}private int dfs(int[] nums,int start,int end){int[] dp = new int[2];dp[0] = nums[start];if(start < end){dp[1] = Math.max(nums[start],nums[start+1]);}for(int i = start+2;i <= end;i++){int j = i - start;dp[j % 2] = Math.max(dp[(j-1) % 2],dp[(j-2) % 2] + nums[i]); }return Math.max(dp[0],dp[1]);}
}

面试题91:

面试题91

问题:

​ 一排n幢房子要粉刷成红色、绿色和蓝色,不同房子被粉刷成不同颜色的成本不同。要求任意相邻的两幢房子的颜色都不一样。

解决方案:
  1. 当计算粉刷标记为i的房子时的成本,得先考虑标记i-1的房子的颜色。因此,需要3个表达式,r(i)表示粉刷红色、g(i)表示粉刷绿色、b(i)表示粉刷蓝色。
  2. 如果标记i的房子粉刷红色时,那么标记i-1的房子可以被粉刷为绿色或蓝色,r(i) = min(g(i-1),b(i-1))+ costs[i]。如果标记i的房子粉刷绿色时,那么标记i-1的房子可以被粉刷为红色或蓝色,g(i) = min(r(i-1),b(i-1))+ costs[i]。如果标记i的房子粉刷蓝色时,那么标记i-1的房子可以被粉刷为绿色或红色,b(i) = min(g(i-1),r(i-1))+ costs[i]。
源代码:
class Solution {public int minCost(int[][] costs) {int len = costs.length;//将三个一维数组合成为一个二维数组int[][] dp = new int[3][2];for(int i = 0;i < 3;i++){dp[i][0] = costs[0][i];}for(int i = 1;i < len;i++){for(int j = 0;j < 3;j++){//计算另外两种颜色的成本int result1 = dp[(j + 1) % 3][(i - 1) % 2];int result2 = dp[(j + 2) % 3][(i - 1) % 2];dp[j][i % 2] = Math.min(result1,result2) + costs[i][j];}}int last = (len-1) % 2;return Math.min(Math.min(dp[0][last],dp[1][last]),dp[2][last]);}
}

面试题92:

面试题92

问题:

​ 输入一个只包含‘0’和‘1’的字符串,至少需要翻转几个字符,才可以使翻转之后的字符串中所有的‘0’位于‘1’的前面。

解决方案:
  1. 由于翻转下标为i的字符依赖于前i个字符翻转之后的最后一个字符是‘0’还是‘1’,因此要分两种情况讨论,假设f(i)是翻转之后最后一个字符为0的函数,g(i)为翻转之后最后一个字符为1的函数。
  2. 如果下标为i的字符是‘0’,那么f(i)= f(i-1)不需要进行翻转;如果下标为i的字符是‘1’,那么f(i) = f(i-1)+ 1。如果下标为i的字符是‘0’,那么g(i) = min(f(i-1),g(i-1))+ 1,因为当我们将下标为i的字符翻转为‘1’时,那么不管下标i-1的字符是0或1都可以;如果下标为i的字符是‘1’,那么g(i)= min(f(i-1),g(i-1)),因为下标为i的字符已经为‘1’了,不需要翻转。
源代码:
class Solution {public int minFlipsMonoIncr(String s) {int len = s.length();int[][] dp = new int[2][2];char ch = s.charAt(0);dp[0][0] = ch == '0'?0:1;dp[1][0] = ch == '0'?1:0;for(int i = 1;i < len;i++){char sh = s.charAt(i);int result1 = dp[0][(i - 1) % 2];int result2 = dp[1][(i - 1) % 2];dp[0][i % 2] = result1 + (sh == '0'?0:1);dp[1][i % 2] = Math.min(result1,result2) + (sh == '1'?0:1); }return Math.min(dp[0][(len - 1) % 2],dp[1][(len - 1) % 2]);}
}

面试题93:

面试题93

问题:

​ 输入一个没有重复数字的单调递增的数组,数组中至少有3个数字,请问数组中最长的斐波那契数列的长度是多少。

解决方案:
  1. 将数组记为A,A[i]表示数组中下标为i的数字。对于每个j(0≤j<i),A[j]都有可能是在某个斐波那契数列中A[i]前面的一个数字。如果存在一个k(0≤k< j)满足A[k]+A[j]=A[i],那么这3个数字就组成了一个斐波那契数列。这个以A[i]为结尾、前一个数字是A[j]的斐波那契数列是在以A[j]为结尾、前一个数字是A[k]的序列的基础上增加一个数字A[i],因此前者的长度是在后者的长度的基础上加1。
  2. 由于状态转移方程有两个参数i和j,因此需要一个二维数组来缓存f(i,j)的计算结果。i对应二维数组的行号,j对应二维数组的列号。由于i大于j,因此实际上只用到了二维数组的左下角部分。如果数组的长度是n,那么i的取值范围为1~n-1,而j的取值范围为0~n-2。
源代码:
class Solution {public int lenLongestFibSubseq(int[] arr) {int len = arr.length;//使用map数组记录每个数字在数组中的下标Map<Integer,Integer> map = new HashMap<>();for(int i = 0;i < len;i++){map.put(arr[i],i);}int[][] dp = new int[len][len];int result = 2;for(int i = 1;i < len;i++){for(int j = 0;j < i;j++){//判断数组中是否存在一个数字 arr[k]满足arr[k]=arr[i]-arr[j]。int k = map.getOrDefault(arr[i]-arr[j],-1);//如果存在,就在f(j,k)的基础上加一dp[i][j] = k >= 0 && k < j?dp[j][k] + 1:2;result = Math.max(result,dp[i][j]);}}return result > 2?result:0;}
}

面试题94:

面试题94

问题:

​ 输入一个字符串,请问至少需要分割几次才可以使分割出的每个字符串都是回文。

解决方案:
  1. 假设字符串为S,下标为i的字符为S[i],下标从j到i的子字符串为S[j…i]。用 f(i)表示从下标为0到i的子字符串S[0…i]的符合条件的最少分割次数。如果字符串的长度是n,那么f(n-1)就是问题的解。
  2. 如果子字符串S[0…i]本身就是一个回文,那么不需要分割就符合要求,此时f(i)等于0。如果子字符串S[0…i]不是一个回文,那么对每个下标j(1≤j≤i)逐一判断子字符串S[j…i]是不是回文。如果是回文,那么这就是一个有效的分割方法,此时的分割次数相当于子字符串S[0…j-1]的分割次数再加1,因为这是将子字符串S[0…j-1]按照要求分割之后再在S[j-1]和S[j]这两个字符中间再分割一次。因此,f(i)就是所有符合条件的j对应的f(j-1)的最小值加1。
源代码:
class Solution {public int minCut(String s) {int len = s.length();//使用二维数组记录j到i是否回文boolean[][] flag = new boolean[len][len];for(int i = 0;i < len;i++){for(int j = 0;j <= i;j++){char ch1 = s.charAt(i);char ch2 = s.charAt(j);//i <= j+1用于判断i和j相邻的情况、flag[j+1][i-1]用于判断j到i不相邻的情况if(ch1 == ch2 && (i <= j+1 || flag[j+1][i-1])){flag[j][i] = true;}}}int[] dp = new int[len];for(int i = 0;i < len;i++){//如果0到i是回文数,那么就不需要分割if(flag[0][i]){dp[i] = 0;}else{//先做最坏的打算,字符需要分割成一个一个的字符。例如abcd,就需要分割3次dp[i] = i;for(int j = 1;j <= i;j++){//如果j到i是回文数,那么就在dp【j-1】切割次数的基础上加一if(flag[j][i]){dp[i] = Math.min(dp[i],dp[j-1] + 1);}}}}return dp[len-1];}
}

相关文章:

剑指Offer题目笔记27(动态规划单序列问题)

面试题89&#xff1a; 问题&#xff1a; ​ 输入一个数组表示某条街道上的一排房屋内财产的数量。相邻两栋房屋不能同时被盗&#xff0c;问小偷能偷取到的最多财物。 解决方案一&#xff08;带缓存的递归&#xff09;&#xff1a; 解决方案&#xff1a; 由于有报警系统&…...

撸代码时,有哪些习惯一定要坚持?

我从2011年开始做单片机开发&#xff0c;一直保持以下撸代码的习惯。 1.做好代码版本管理 有些人&#xff0c;喜欢一个程序干到底&#xff0c;直到实现全部的产品功能&#xff0c;我以前做51单片机的项目就是这样。 如果功能比较多的产品&#xff0c;我不建议这样做&#xff0…...

【leetcode面试经典150题】17.罗马数字转整数(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…...

前后端开发之——文章分类管理

原文地址&#xff1a;前后端开发之——文章分类管理 - Pleasure的博客 下面是正文内容&#xff1a; 前言 上回书说到 文章管理系统之添加文章分类。就是通过点击“新建文章分类”按钮从而在服务端数据库中增加一个文章分类。 对于文章分类这个对象&#xff0c;增删改查属于配…...

第12届蓝桥杯省赛 ---- C/C++ C组

文章目录 1. ASC2. 空间3. 卡片4. 相乘5. 路径6.时间显示7.最少砝码8. 杨辉三角形9. 左孩子右兄弟 第12届蓝桥杯省赛&#xff0c;C/C C组真题&#xff0c;第10题不是很清楚&#xff0c;题解不敢乱放&#x1f601;&#x1f601;&#x1f601; 1. ASC 额。。。。 #include <i…...

IVS模型解释

核心思路 【Implied volatility surface predictability: The case of commodity markets】 半参数化模型&#xff1a;利用各种参数(或者因子)对隐含波动率进行降维&#xff08;静态参数化因子模型&#xff09;&#xff0c;对参数化因子的时间序列进行间接的建模 基于非对称…...

通用开发技能系列:Git

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能Git进行学习 1.为什么使用版本控制系统 版本控制系统可以解决的问题 代码备份很重要版本控制很重要协同工作很重要责任追溯很重要 常见的版本控制系统 Gi…...

最新怎么订阅OnlyFans上喜欢的博主,详细教程

大家好&#xff0c;本文教大家如何用虚拟信用卡在 Onlyfans 订阅&#xff0c;链接在浏览器打开地址https://bewildcard.com/i/GPT310&#xff0c;虚拟卡开好之后&#xff0c;用支付宝充值就可以进行订阅OnlyFans平台的博主了。 什么是OnlyFans&#xff1f; OnlyFans 是一个提…...

Mysql故障和优化

一、MySQL故障 二、MySQL优化 1.硬件优化&#xff1a; 2.数据库设计与规划 1.提前估计数据量&#xff0c;使用什么存储引擎 2.数据库服务器专机专用&#xff0c;避免额外的服务可能导致的性能下降和不稳定性 3.增加多台服务器&#xff0c;以达到稳定、高效的效果。主从同步、…...

Windows系统C盘空间优化进阶:磁盘清理与Docker日志管理

Windows系统C盘空间优化进阶&#xff1a;磁盘清理与Docker日志管理 文章目录 Windows系统C盘空间优化进阶&#xff1a;磁盘清理与Docker日志管理磁盘清理工具 使用“运行”命令访问磁盘清理利用存储感知自动管理空间清理WinSxS文件夹结合手动清理策略 小结删除临时文件总结&…...

14届蓝桥杯 C/C++ B组 T7 子串简写 (字符串)

采用存储目标字符下标的方法&#xff0c;此题的想法比较新奇&#xff0c;故予以记录。 存好下标之后&#xff0c;可以先定位好启始的字符&#xff0c;然后去搜结尾字符符合长度k并且最靠近启始字符的下标&#xff0c;找到之后可以直接取到这个下标之后的所有下标&#xff0c;因…...

Android 系统大致启动流程

Android启动流程大体为&#xff1a;BootRom -> BootLoader -> Kernel -> Init -> Zygote -> SystemServer ->Launcher 1、Loader层 1.1、Boot ROM 电源按下&#xff0c;引导芯片代码开始从预定义的地方&#xff08;固化在ROM&#xff09;开始执行&#xff0…...

【Web】2024红明谷CTF初赛个人wp(2/4)

目录 ezphp playground 时间原因只打了2个小时&#xff0c;出了2道&#xff0c;简单记录一下 ezphp 参考文章 PHP filter chains: file read from error-based oracle https://github.com/synacktiv/php_filter_chains_oracle_exploit 用上面的脚本爆出部分源码&#xff…...

stable-diffusion-webui安装教程

现在AI开始进入绘画领域,并且能自动根据文本来创建图片出来,这是一个划时代的进步。 这时候,我也不能落后,要紧跟上时代的步伐,那么也来学习一下stable-diffusion的使用,这样也算多一项对技术的认识,提高对AI的认知。 从网上看到很多stable-diffusion-webui的安装,其…...

如何魔改 diffusers 中的 pipelines

如何魔改 diffusers 中的 pipelines 整个 Stable Diffusion 及其 pipeline 长得就很适合 hack 的样子。不管是通过简单地调整采样过程中的一些参数&#xff0c;还是直接魔改 pipeline 内部甚至 UNet 内部的 Attention&#xff0c;都可以实现很多有趣的功能或采样生图结果。 本…...

解放办公室的利器!让证卡打印机轻松应对繁忙工作场景

在现代办公室中&#xff0c;证卡打印机已经成为不可或缺的工作利器。但是&#xff0c;在繁忙的工作场景中&#xff0c;我们经常忽视了它的保养和清洁。然而&#xff0c;正确的清洁和维护不仅可以延长打印机的寿命&#xff0c;还可以提高工作效率&#xff0c;确保每一次打印都是…...

2012年认证杯SPSSPRO杯数学建模A题(第二阶段)蜘蛛网全过程文档及程序

2012年认证杯SPSSPRO杯数学建模 A题 蜘蛛网 原题再现&#xff1a; 第二阶段问题   现在我们假设一个具体的环境。假设有一个凸多边形的区域&#xff0c;蜘蛛准备在这个区域&#xff08;或其一部分&#xff09;上结一张网。   问题一&#xff1a; 在区域的边界上安置有若干…...

ES学习日记(七)-------Kibana安装和简易使用

前言 首先明确一点&#xff0c;Kibana是一个软件&#xff0c;不是插件。 Kibana 是一款开源的数据分析和可视化平台&#xff0c;它是 Elastic stack 成员之一&#xff0c;设计用于和Elasticsearch 协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索&#xff0c;…...

react 父子组件的渲染机制 | 优化手段

文章目录 父子组件的渲染机制优化手段与实践写法父组件&#xff1a;下发stateprops.children 传递无状态组件props传递组件 React.memo缓存子组件与useCallback结合 父子组件的渲染机制 渲染分初次渲染和重新渲染 React组件会在两种情况下发生重新渲染 当组件自身的state发生…...

elementPlus el-table动态列扩展及二维表格

1、循环列数据源&#xff0c;动态生成列 <template><div><el-table ref"table" :data"pageData.tableData" stripe style"width: 100%"><el-table-column v-for"column in pageData.columns" :key"column.p…...

Linux hostid命令实战:如何用它搞定软件授权和网络许可证管理

Linux hostid命令实战&#xff1a;如何用它搞定软件授权和网络许可证管理 在Linux系统管理中&#xff0c;软件授权和网络许可证管理一直是让开发者头疼的问题。想象一下&#xff0c;你刚部署了一套价值不菲的商业软件&#xff0c;结果因为授权问题导致服务中断&#xff1b;或者…...

实战:利用‘语义锚定’技术,防止竞品通过 AI 生成的内容覆盖你的核心词条

各位编程专家、技术领袖们&#xff0c;大家好&#xff01;今天&#xff0c;我们齐聚一堂&#xff0c;探讨一个在AI时代日益突出的挑战&#xff1a;如何防止竞争对手利用AI生成的内容&#xff0c;稀释甚至覆盖我们品牌的核心技术词条。这不仅仅是SEO的攻防战&#xff0c;更是品牌…...

手把手教你解决Fabric2.2链码部署中的权限问题(test-network环境)

深度解析Fabric2.2链码部署中的权限陷阱与系统级解决方案 当你在深夜的终端前反复执行deployCC命令&#xff0c;却只收获冰冷的status: 500错误时&#xff0c;那种挫败感每个Hyperledger Fabric开发者都深有体会。权限问题就像隐形的地雷&#xff0c;往往在你最意想不到的地方引…...

VMware里玩转AD域:Windows Server 2016域控搭建避坑指南(含DNS配置详解)

VMware虚拟化实战&#xff1a;Windows Server 2016域控部署的七个关键陷阱与解决方案 在虚拟化环境中搭建Active Directory域服务&#xff0c;远比物理机部署更具挑战性。许多学习者在VMware Workstation中按照标准教程操作后&#xff0c;仍会遇到客户端无法加域、DNS解析失败等…...

终极指南:MiroFish群体智能引擎深度解析与实战应用

终极指南&#xff1a;MiroFish群体智能引擎深度解析与实战应用 【免费下载链接】MiroFish A Simple and Universal Swarm Intelligence Engine, Predicting Anything. 简洁通用的群体智能引擎&#xff0c;预测万物 项目地址: https://gitcode.com/GitHub_Trending/mi/MiroFis…...

【Multisim实战指南】工具栏全解析:从入门到高效设计

1. Multisim工具栏全景概览 刚接触Multisim时&#xff0c;面对密密麻麻的工具栏图标&#xff0c;很多新手都会感到无从下手。其实这些工具栏就像电工师傅的工具腰带&#xff0c;每个工具都有其专属用途。经过多年使用&#xff0c;我发现合理运用工具栏能提升至少50%的设计效率。…...

Kalidokit:3D动作捕捉与虚拟角色驱动的开源解决方案

Kalidokit&#xff1a;3D动作捕捉与虚拟角色驱动的开源解决方案 【免费下载链接】kalidokit Blendshape and kinematics calculator for Mediapipe/Tensorflow.js Face, Eyes, Pose, and Finger tracking models. 项目地址: https://gitcode.com/gh_mirrors/ka/kalidokit …...

Qwen3-1.7B应用案例:快速构建智能问答助手完整流程

Qwen3-1.7B应用案例&#xff1a;快速构建智能问答助手完整流程 1. 项目概述与准备 1.1 Qwen3-1.7B模型简介 Qwen3-1.7B是阿里巴巴开源的通义千问系列语言模型中的轻量级版本&#xff0c;具有17亿参数规模。该模型在保持较高推理性能的同时&#xff0c;对硬件资源需求相对友好…...

HunyuanVideo-Foley开源大模型部署:24G显存专用调度策略深度解读

HunyuanVideo-Foley开源大模型部署&#xff1a;24G显存专用调度策略深度解读 1. 镜像概述与核心价值 HunyuanVideo-Foley 是一款集视频生成与音效生成于一体的多模态大模型&#xff0c;本镜像专为RTX 4090D 24GB显存环境深度优化。相比通用部署方案&#xff0c;本镜像通过以下…...

SEO_长期有效的SEO策略与持续优化技巧分享

SEO:长期有效的SEO策略与持续优化技巧分享 在当今数字化时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是每个网站主人和数字营销人员必须掌握的技能之一。无论你是新手还是有经验的SEO专家&#xff0c;长期有效的SEO策略和持续优化技巧都是提升网站排名、增加流量的…...