面试算法高频08-动态规划-02

动态规划练习题

题目描述

给定两个字符串 text1text2,要求返回这两个字符串的最长公共子序列。例如对于字符串 “ABAZDC” 和 “BACBAD”,需找出它们最长的公共子序列。子序列是指在不改变其余字符相对位置的情况下,从原始字符串中删除某些字符(也可以不删除)后形成的新字符串。

最优解(Python)
def longestCommonSubsequence(text1, text2):m, n = len(text1), len(text2)dp = [[0] * (n + 1) for _ in range(m + 1)]for i in range(1, m + 1):for j in range(1, n + 1):if text1[i - 1] == text2[j - 1]:dp[i][j] = dp[i - 1][j - 1] + 1else:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])return dp[m][n]
解析
  1. 动态规划思路:本题采用动态规划方法,核心是通过分析子问题的解来构建最终问题的解。
  2. 状态定义:定义二维数组 dp[i][j] 表示 text1 的前 i 个字符和 text2 的前 j 个字符的最长公共子序列长度。
  3. 状态转移方程
    • text1[i - 1] == text2[j - 1] 时,说明当前字符相等,此时 dp[i][j] 等于 dp[i - 1][j - 1] + 1 ,即在前 i - 1 和前 j - 1 个字符最长公共子序列基础上长度加1。
    • text1[i - 1] != text2[j - 1] 时,dp[i][j]dp[i - 1][j]dp[i][j - 1] 中的较大值,因为此时最长公共子序列要么是 text1i - 1 个字符与 text2j 个字符的最长公共子序列,要么是 text1i 个字符与 text2j - 1 个字符的最长公共子序列。
  4. 边界条件dp[0][j] = 0 表示 text1 为空字符串时,最长公共子序列长度为0;dp[i][0] = 0 表示 text2 为空字符串时,最长公共子序列长度为0 。
  5. 时间复杂度:由于使用了两层嵌套循环遍历两个字符串,时间复杂度为 O ( m × n ) O(m \times n) O(m×n),其中 m m m n n n 分别是 text1text2 的长度。
  6. 空间复杂度:使用了一个二维数组 dp 存储中间结果,空间复杂度为 O ( m × n ) O(m \times n) O(m×n) ,不过可以通过滚动数组优化为 O ( m i n ( m , n ) ) O(min(m, n)) O(min(m,n))

题目描述

题目链接为https://leetcode-cn.com/problems/climbing-stairs/description/ ,假设你正在爬楼梯,需要 n 阶才能到达楼顶。每次你可以爬 12 个台阶,要求计算有多少种不同的方法可以爬到楼顶 。其中,n 是一个正整数,且满足 1 <= n <= 45 。例如:

  • 当输入 n = 2 时,输出为 2,因为有两种方法可以爬到楼顶,分别是 “1 阶 + 1 阶” 和 “2 阶” 。
  • 当输入 n = 3 时,输出为 3,因为有三种方法可以爬到楼顶,分别是 “1 阶 + 1 阶 + 1 阶” 、“1 阶 + 2 阶” 、“2 阶 + 1 阶” 。
最优解(Python)
def climbStairs(n):if n <= 2:return na, b = 1, 2for _ in range(2, n):a, b = b, a + breturn b
解析
  1. 动态规划思路:本题可采用动态规划的方法求解。动态规划的核心是将原问题分解为多个子问题,通过求解子问题并保存结果来避免重复计算,最终得到原问题的解。
  2. 状态定义:定义 f(n) 表示爬到第 n 阶楼梯的不同方法数。
  3. 状态转移方程:因为每次可以爬 1 阶或 2 阶,所以爬到第 n 阶的方法数等于爬到第 n - 1 阶的方法数加上爬到第 n - 2 阶的方法数,即 f(n) = f(n - 1) + f(n - 2) 。这是一个类似斐波那契数列的递推关系。
  4. 边界条件:当 n = 1 时,只有一种方法(爬 1 阶),即 f(1) = 1 ;当 n = 2 时,有两种方法(两次爬 1 阶或一次爬 2 阶) ,即 f(2) = 2
  5. 代码实现细节:代码中使用了两个变量 ab 分别表示 f(n - 2)f(n - 1) ,通过不断更新这两个变量来计算 f(n) 。循环从 n = 2 开始,每次迭代更新 ab 的值,最终 b 存储的就是爬到第 n 阶的方法数。
  6. 复杂度分析
    • 时间复杂度:代码中只进行了一次循环,循环次数为 n - 2 次,每次循环的操作都是常数时间的,所以时间复杂度为 O ( n ) O(n) O(n)
    • 空间复杂度:只使用了常数个额外变量(ab ),所以空间复杂度为 O ( 1 ) O(1) O(1) 。 这种空间复杂度为常数的实现方式是对动态规划空间优化后的结果,相较于使用数组存储所有子问题结果(空间复杂度为 O ( n ) O(n) O(n) )更为高效。

题目描述

题目链接为https://leetcode-cn.com/problems/triangle/description/ ,给定一个三角形 triangle ,它是一个二维列表,其中 triangle[i] 表示三角形第 i 行的数字列表。要求找到从三角形顶部到底部的最小路径和。在每一步只能移动到下一行中相邻的节点上。例如,对于三角形 [[2],[3,4],[6,5,7],[4,1,8,3]] ,从顶部到底部的最小路径和是 11(路径为 2→3→5→1 )。

最优解(Python)
def minimumTotal(triangle):n = len(triangle)# 从倒数第二行开始向上遍历for i in range(n - 2, -1, -1):for j in range(len(triangle[i])):# 状态转移:选择下方相邻两个数中较小的,加上当前数triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1])return triangle[0][0]
解析
  1. 动态规划思路:采用动态规划来解决此问题。动态规划的关键在于将问题分解为多个子问题,并利用子问题的解来构建最终问题的解。
  2. 状态定义:把 triangle[i][j] 看作状态,表示从三角形第 i 行第 j 列这个位置到底部的最小路径和。
  3. 状态转移方程:对于第 i 行第 j 列的元素,它下一步可以移动到下一行的第 j 列或者第 j + 1 列。所以 triangle[i][j] 的最小路径和等于当前位置的值加上下一行相邻两个位置中较小的那个位置的最小路径和,即 triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1])
  4. 遍历顺序:从三角形的倒数第二行开始向上遍历,因为最底层的元素到底部的最小路径和就是其自身的值,以此为基础向上递推。
  5. 边界条件:最底层的元素不需要进行额外计算,其自身值就是从它到底部的最小路径和(因为已经是最底层了)。
  6. 复杂度分析
    • 时间复杂度:使用了两层嵌套循环,外层循环遍历行数,内层循环遍历每行的元素,总的时间复杂度为 O ( n 2 ) O(n^2) O(n2) ,其中 n n n 是三角形的行数。
    • 空间复杂度:直接在原三角形数组上进行操作,没有使用额外的与问题规模相关的空间,所以空间复杂度为 O ( 1 ) O(1) O(1) 。 这种在原数据结构上直接修改来保存中间结果的方式,有效避免了额外的空间开销。

题目描述

链接:https://leetcode-cn.com/problems/maximum-subarray/ 。

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。例如,输入 nums = [-2,1,-3,4,-1,2,1,-5,4] ,输出为 6 ,因为连续子数组 [4,-1,2,1] 的和最大,为 6

最优解(Python)
def maxSubArray(nums):n = len(nums)if n == 0:return 0dp = [0] * ndp[0] = nums[0]max_sum = dp[0]for i in range(1, n):dp[i] = max(nums[i], dp[i - 1] + nums[i])max_sum = max(max_sum, dp[i])return max_sum
解析
  1. 动态规划思路:本题运用动态规划方法。动态规划的核心是将复杂问题分解为多个相互关联的子问题,通过求解子问题并保存结果,避免重复计算,从而高效地解决原问题。
  2. 状态定义:定义 dp[i] 表示以 nums[i] 结尾的连续子数组的最大和 。
  3. 状态转移方程:对于 dp[i] ,它有两种情况。一种是只取 nums[i] 这一个元素作为子数组,另一种是将 nums[i] 加入到以 nums[i - 1] 结尾的连续子数组中。所以状态转移方程为 dp[i] = max(nums[i], dp[i - 1] + nums[i])
  4. 边界条件:当 i = 0 时,dp[0] = nums[0] ,因为此时以 nums[0] 结尾的连续子数组就是它本身。
  5. 求解过程:在循环中,每计算出一个 dp[i] ,就更新 max_summax_sum 记录的是到当前位置为止,所有以不同元素结尾的连续子数组中的最大和。
  6. 复杂度分析
    • 时间复杂度:代码中只有一层循环,循环次数为数组的长度 n ,每次循环内的操作都是常数时间的,所以时间复杂度为 O ( n ) O(n) O(n)
    • 空间复杂度:使用了一个长度为 n 的数组 dp 来保存中间结果,所以空间复杂度为 O ( n ) O(n) O(n) 。不过,还可以进一步优化,将空间复杂度降为 O ( 1 ) O(1) O(1) ,即不使用 dp 数组,而是用一个变量来记录以当前元素结尾的最大子数组和。优化后的代码如下:
def maxSubArray(nums):n = len(nums)if n == 0:return 0cur_sum = nums[0]max_sum = nums[0]for i in range(1, n):cur_sum = max(nums[i], cur_sum + nums[i])max_sum = max(max_sum, cur_sum)return max_sum

此时,只使用了几个额外的变量,空间复杂度为 O ( 1 ) O(1) O(1)

题目描述(另一题,链接:https://leetcode-cn.com/problems/maximum-product-subarray/description/ )

给定一个整数数组 nums ,找出一个乘积最大的连续子数组。子数组最少包含一个元素。例如,输入 nums = [2,3,-2,4] ,输出为 6 ,因为子数组 [2,3] 有最大乘积 6

最优解(Python)
def maxProduct(nums):n = len(nums)if n == 0:return 0max_ending_here = min_ending_here = res = nums[0]for i in range(1, n):# 暂存当前的最大值,用于计算新的最小值temp_max = max_ending_heremax_ending_here = max(nums[i], max_ending_here * nums[i], min_ending_here * nums[i])min_ending_here = min(nums[i], temp_max * nums[i], min_ending_here * nums[i])res = max(res, max_ending_here)return res
解析
  1. 动态规划思路:同样采用动态规划策略。由于数组中存在负数,负数与负数相乘可能得到更大的乘积,所以不能简单地用与最大子数组和类似的方法。需要同时记录以当前元素结尾的最大乘积子数组和最小乘积子数组。
  2. 状态定义:定义 max_ending_here 表示以当前元素 nums[i] 结尾的最大乘积子数组的乘积,min_ending_here 表示以当前元素 nums[i] 结尾的最小乘积子数组的乘积 。
  3. 状态转移方程
    • 对于 max_ending_here ,它的取值可能是当前元素 nums[i] ,也可能是当前元素与之前的 max_ending_here 相乘,还可能是当前元素与之前的 min_ending_here 相乘(因为负负得正,可能得到更大的值),即 max_ending_here = max(nums[i], max_ending_here * nums[i], min_ending_here * nums[i])
    • 对于 min_ending_here ,它的取值可能是当前元素 nums[i] ,也可能是当前元素与之前的 max_ending_here 相乘(得到较小的值),还可能是当前元素与之前的 min_ending_here 相乘,即 min_ending_here = min(nums[i], temp_max * nums[i], min_ending_here * nums[i]) 。这里的 temp_max 是暂存的上一轮的 max_ending_here ,用于计算新的 min_ending_here
  4. 边界条件:当 i = 0 时,max_ending_here = min_ending_here = nums[0]
  5. 求解过程:在循环中,每次更新 max_ending_heremin_ending_here 后,都用 res 记录到当前位置为止的最大乘积,最后返回 res
  6. 复杂度分析
    • 时间复杂度:只有一层循环,循环次数为数组长度 n ,每次循环内操作是常数时间,所以时间复杂度为 O ( n ) O(n) O(n)
    • 空间复杂度:只使用了几个额外变量,空间复杂度为 O ( 1 ) O(1) O(1)

题目描述

题目链接为https://leetcode-cn.com/problems/coin-change/description/ 。给定不同面额的硬币 coins 列表和一个总金额 amount ,编写一个函数来计算可以凑成总金额所需的最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。假设每种硬币的数量是无限的。例如:

  • 输入 coins = [1, 2, 5]amount = 11 ,输出为 3 ,因为 11 = 5 + 5 + 1 ,最少需要 3 枚硬币。
  • 输入 coins = [2]amount = 3 ,输出为 -1 ,因为无法用面额为 2 的硬币凑出金额 3
最优解(Python)
def coinChange(coins, amount):dp = [amount + 1] * (amount + 1)dp[0] = 0for i in range(1, amount + 1):for coin in coins:if coin <= i:dp[i] = min(dp[i], dp[i - coin] + 1)return dp[amount] if dp[amount] != amount + 1 else -1
解析
  1. 动态规划思路:本题使用动态规划来解决。动态规划的核心在于将问题分解为多个子问题,通过求解子问题并保存结果,避免重复计算,最终得到原问题的解。
  2. 状态定义:定义 dp[i] 表示凑成金额 i 所需的最少硬币个数。
  3. 状态转移方程:对于金额 i ,遍历所有硬币面额 coin ,如果 coin <= i ,那么 dp[i] 可以由 dp[i - coin] + 1 得到(dp[i - coin] 是凑成金额 i - coin 所需的最少硬币个数,加上一枚面额为 coin 的硬币就可以凑成金额 i ),并且取 dp[i]dp[i - coin] + 1 中的较小值,即 dp[i] = min(dp[i], dp[i - coin] + 1)
  4. 边界条件dp[0] = 0 ,表示凑成金额 0 不需要任何硬币。初始化 dp 数组其他元素为 amount + 1 ,这是一个不可能达到的较大值,用于后续比较更新。
  5. 求解过程:通过两层循环,外层循环遍历从 1amount 的所有金额,内层循环遍历所有硬币面额,不断更新 dp 数组。最后,如果 dp[amount] 仍然是初始的 amount + 1 ,说明无法凑出该金额,返回 -1 ;否则返回 dp[amount]
  6. 复杂度分析
    • 时间复杂度:有两层循环,外层循环次数为 amount 次,内层循环次数为硬币种类数(假设为 m ),所以时间复杂度为 O ( m × a m o u n t ) O(m \times amount) O(m×amount)
    • 空间复杂度:使用了一个长度为 amount + 1 的数组 dp 来保存中间结果,所以空间复杂度为 O ( a m o u n t ) O(amount) O(amount)

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

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

相关文章

【人工智能学习-01-01】20250419《数字图像处理》复习材料的word合并PDF,添加页码

前情提要 20250419今天是上师大继续教育人工智能专升本第一学期的第一次线下课。 三位老师把视频课的内容提炼重点再面授。&#xff08;我先看了一遍视频&#xff0c;但是算法和图像都看不懂&#xff0c;后来就直接挂分刷满时间&#xff0c;不看了&#xff09; 今天是面对面授…

AI写代码工具分享:Cursor 高效使用攻略与实战秘籍

写在前面 在软件开发领域,效率和生产力是永恒的追求。集成开发环境(IDE)作为开发者的核心工具,其能力直接影响着开发速度和质量。近年来,人工智能(AI)的浪潮席卷了各个行业,编程领域也不例外。Cursor IDE 正是这股浪潮中的佼佼者,它以 AI-First 的理念,在广受欢迎的…

守护进程编程

守护进程编程 守护进程的含义 定义 守护进程&#xff08;Daemon Process&#xff09;是在后台运行的进程&#xff0c;它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程&#xff0c;它在系统后台运行&#xff0c;为系统或其他…

在复杂性的迷宫里寻找路标 —— 读《人月神话》有感

初读《人月神话》时&#xff0c;正值参与的第一个大型项目陷入泥潭&#xff1a;需求像不断膨胀的气球&#xff0c;团队规模从 10 人扩充到 30 人&#xff0c;进度却像被灌了铅的钟表&#xff0c;指针越来越沉重。布鲁克斯在书中写下的 "向进度落后的项目增加人力&#xff…

SpringCloud Alibaba微服务工程搭建

前言 在讲微服务工程的搭建之前&#xff0c;我们先分析下为什么要使用微服务呢&#xff1f; 1、单体应用的痛点 维护困难&#xff1a;代码臃肿&#xff0c;牵一发而动全身。扩展性差&#xff1a;无法按需扩展特定功能&#xff0c;只能整体扩容。技术栈僵化&#xff1a;难以引…

flutter json解析增强

依赖:xxf_json 反序列化兼容特征一览表 类型\是否兼容 int double num string bool int yes yes yes yes yes double yes yes yes yes yes num yes yes yes yes yes string yes yes yes yes yes bool yes yes yes yes yes 专业词语 .g…

Neo4j初解

Neo4j 是目前应用非常广泛的一款高性能的 NoSQL 图数据库&#xff0c;其设计和实现专门用于存储、查询和遍历由节点&#xff08;实体&#xff09;、关系&#xff08;边&#xff09;以及属性&#xff08;键值对&#xff09;构成的图形数据模型。它的核心优势在于能够以一种自然且…

学习MySQL的第十天

一、MySQL的数据类型 1.MySQL的数据类型 2.常见的数据类型的属性 二、整数类型 三、浮点类型 REAL默认就是DOUBLE。如果你把SQL模式设定为启用“REAL_AS_FLOAT”,那么,MySQL就认为REAL是FLOAT。如果要启用“REAL_AS_FLOAT”,可以通过以下SQL语句实现: SET sql_mode &…

ubuntu24.04上使用qemu+buildroot+uboot+linux+tftp+nfs模拟搭建vexpress-ca9嵌入式linux开发环境

1 准备工作 1.1 安装依赖工具 sudo apt-get update && sudo apt-get install build-essential git bc flex libncurses5-dev libssl-dev device-tree-compiler1.2 安装arm交叉编译工具链 sudo apt install gcc-arm-linux-gnueabihf安装之后&#xff0c;在终端输入ar…

ubuntu 22.04 使用ssh-keygen创建ssh互信账户

现有两台ubuntu 22.04服务器&#xff0c;ip分别为192.168.66.88和192.168.88.66。需要将两台服务器创建新用户并将新用户做互信。 创建账户 adduser user1 # 如果此用户不想使用密码&#xff0c;直接一直回车就行&#xff0c;创建的用户是没法使用用户密码进行登陆的 su - …

【PCIE配置空间】

1 PCIE配置空间 1.1 软件如何知道PCIE设备是Swith&#xff0c;RC还是EP&#xff1f; –软件通过读取寄存器信息。 PCIE配置空间• PCIE寄存器&#xff1b;--PCIE配置协议规定必须实现的空间。--PCIE存在两种配置空间Type0/Type1;--Type0配置空间EP设备必须实现&#xff1b;-…

Android 热点二维码简单示例

Android 热点二维码简单示例 一、前言 Android 原生设置有热点二维码分享功能&#xff0c;有些系统应用也会有这个需求。 下面看看是如何实现的。 本文是一个比较简单的内容。 二、热点二维码生成实现 1、效果 整个应用就一个普通的Activity&#xff0c;显示一个按钮和二维…

uv:重新定义Python开发效率的下一代工具链

在Python生态系统中&#xff0c;包管理和项目工具链的复杂性一直是开发者面临的一大挑战。从依赖管理、虚拟环境创建到多版本Python切换&#xff0c;传统的工具链&#xff08;如pip、virtualenv、poetry等&#xff09;虽然功能强大&#xff0c;但操作繁琐、性能不足的问题长期存…

T101D加固平板电脑:无人机地面站的高效智能控制核心

随着无人机技术在应急救援、农业监测、军事侦察等领域的广泛应用&#xff0c;对地面控制设备的要求也日益提高。鲁成伟业推出的T101D加固平板电脑凭借其高性能、强防护和专业化设计&#xff0c;成为无人机地面站的核心控制终端&#xff0c;为复杂环境下的作业提供了可靠支持。 …

Datawhale AI春训营】AI + 新能源(发电功率预测)Task1

赛题链接 官网 新能源发电功率预测赛题进阶方案 下面是ai给的一些建议 新能源发电功率预测赛题进阶方案 一、时序特性深度挖掘 1. 多尺度周期特征 # 分钟级周期编码 train[15min_index] (train[hour]*4 train[minute]//15)# 周周期特征 train[weekday] pd.to_datetime…

山东科技大学深度学习考试回忆

目录 一、填空&#xff08;五个空&#xff0c;十分&#xff09; 二、选择题(五个&#xff0c;十分&#xff09; 三、判断题&#xff08;五个&#xff0c;五分&#xff09; 四、论述题&#xff08;四个&#xff0c;四十分&#xff09; 五、计算题&#xff08;二个&#xff…

Redis线上操作最佳实践有哪些?

大家好&#xff0c;我是锋哥。今天分享关于【Redis线上操作最佳实践有哪些?】面试题。希望对大家有帮助&#xff1b; Redis线上操作最佳实践有哪些? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在使用 Redis 时&#xff0c;尤其是在生产环境中&#xff0c;合理…

mac中的zip文件压缩与压缩文件中指定目录删除

问题 在使用mac的图形界面压缩文件后&#xff0c;往往那个压缩文件中带有__MACOSX文件&#xff0c;但是&#xff0c;这个文件夹又是我们不需要的目录&#xff0c;所有&#xff0c;需要对mac图形化界面压缩后的文件目录进行删除&#xff0c;改如何做&#xff1f; 检查压缩文件…

【记录】服务器用命令开启端口号

这里记录下如何在服务器上开启适用于外界访问的端口号。 方法 1 使用防火墙 1 su &#xff0c;命令 输入密码 切换到root节点 2 开启防火墙 systemctl start firewalld3 配置开放端口 firewall-cmd --zonepublic --add-port8282/tcp --permanent4 重启防火墙 firewall-cmd…

深度学习-torch,全连接神经网路

3. 数据集加载案例 通过一些数据集的加载案例&#xff0c;真正了解数据类及数据加载器。 3.1 加载csv数据集 代码参考如下 import torch from torch.utils.data import Dataset, DataLoader import pandas as pd ​ ​ class MyCsvDataset(Dataset):def __init__(self, fil…