python算法和数据结构刷题[5]:动态规划

动态规划(Dynamic Programming, DP)是一种算法思想,用于解决具有最优子结构的问题。它通过将大问题分解为小问题,并找到这些小问题的最优解,从而得到整个问题的最优解。动态规划与分治法相似,但区别在于动态规划的子问题通常不是相互独立的。

动态规划的核心是解决重复子问题。例如,斐波那

契数列问题,可以通过递归实现,但效率低下,因为会有重复计算。动态规划通过存储已解决的子问题的答案,避免重复计算,从而提高效率。这种方法需要额外的存储空间,是一种空间换时间的策略。

如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。

单维动态规划

斐波那契数列

def fibonacci(n):# 如果n小于等于1,直接返回nif n <= 1:return n# 初始化dp数组,用于存储从0到n的斐波那契数dp = [0] * (n + 1)dp[1] = 1  # 斐波那契数列的第二个数是1# 使用动态规划填充dp数组for i in range(2, n + 1):dp[i] = dp[i - 1] + dp[i - 2]# 返回第n个斐波那契数return dp[n]# 测试代码
print(fibonacci(0))  # 输出 0
print(fibonacci(1))  # 输出 1
print(fibonacci(2))  # 输出 1
print(fibonacci(3))  # 输出 2
print(fibonacci(4))  # 输出 3
print(fibonacci(5))  # 输出 5
print(fibonacci(6))  # 输出 8
print(fibonacci(7))  # 输出 13

70. 爬楼梯 - 力扣(LeetCode)

到达第 n 个台阶的方法数等于到达第 n-1 个台阶和第 n-2 个台阶的方法数之和

class Solution:def climbStairs(self, n: int) -> int:f = [0] * (n + 1)f[0] = f[1] = 1for i in range(2, n + 1):f[i] = f[i - 1] + f[i - 2]return f[n]

118. 杨辉三角 - 力扣(LeetCode)

给出一个整数输出杨辉三角 

class Solution:def generate(self, numRows: int) -> List[List[int]]:dp = [[0] * i for i in range(1, numRows + 1)]for i in range(numRows):dp[i][0] = 1dp[i][i] = 1res = []for i in range(numRows):for j in range(i):if i != 0 and j != 0:dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]res.append(dp[i])return res

 322. 零钱兑换 - 力扣(LeetCode)

背包问题:背包问题通常描述为:给定一组物品,每个物品有一定的价值(value)和重量(weight),需要从中选择一些物品放入一个给定容量的背包中,使得放入背包的物品的总价值最大,同时不超过背包的容量。

完全背包问题 

返回构成该金额所需的最少硬币数量。如果该金额无法通过硬币的任何组合来弥补,则返回 。-1

def coinChange(coins, amount):# 创建一个数组,长度为 amount + 1,初始值为 amount + 1dp = [amount + 1] * (amount + 1)# 金额为0时,需要0个硬币dp[0] = 0# 遍历每个金额for a in range(1, amount + 1):# 遍历每种硬币for coin in coins:# 如果当前硬币面额小于等于当前金额if coin <= a:# 更新 dp[a] 为使用当前硬币后的最少硬币数量dp[a] = min(dp[a], dp[a - coin] + 1)# 如果 dp[amount] 还是初始值,则返回 -1,否则返回 dp[amount]return dp[amount] if dp[amount] != amount + 1 else -1# 示例
coins = [1, 2, 5]
amount = 11
print(coinChange(coins, amount))  # 输出应该是 3

279. 完全平方数 - 力扣(LeetCode)

完全背包问题

def numSquares(n):# 创建一个数组来存储每个数字的最小完全平方数个数,初始值为0dp = [0] * (n + 1)#,用于存储每个数字 i 可以表示为完全平方数之和的最小数量。    # 初始化dp数组,每个位置初始为最大值for i in range(1, n + 1):dp[i] = i  # 最坏的情况是 i 个 1 的平方# 遍历每个数字,更新其最小完全平方数个数for i in range(1, n + 1):j = 1while j * j <= i:dp[i] = min(dp[i], dp[i - j * j] + 1)j += 1# 返回n的最小完全平方数个数return dp[n]# 示例
print(numSquares(12))  # 输出应为 3
print(numSquares(13))  # 输出应为 2,因为 13 = 4 + 9

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

def rob(nums):if not nums:return 0if len(nums) == 1:return nums[0]dp = [0] * len(nums)dp[0] = nums[0]dp[1] = max(nums[0], nums[1])for i in range(2, len(nums)):dp[i] = max(dp[i-1], dp[i-2] + nums[i])return dp[-1]# 示例
nums = [2, 7, 9, 3, 1]
print(rob(nums))  # 输出应该是 12,因为抢第 0、2、4 间房子(2+9+1)

 139. 单词拆分 - 力扣(LeetCode)

def wordBreak(s, wordDict):# 首先创建一个布尔数组 dp,长度为字符串长度加一,初始化所有值为 Falsedp = [False] * (len(s) + 1)# dp[i] 将表示 s 的前 i 个字符是否可以被成功分割dp[0] = True  # 空字符串可以被成功分割# 遍历字符串的每一个字符for i in range(1, len(s) + 1):# 对于每一个可能的结束位置 i,检查所有可能的开始位置 jfor j in range(i):# 如果 dp[j] 为 True,且 s[j:i] 在字典中,那么 dp[i] 也为 Trueif dp[j] and s[j:i] in wordDict:dp[i] = Truebreak  # 找到一个有效的分割就跳出内层循环# 返回 dp[len(s)],它表示整个字符串是否可以被成功分割return dp[len(s)]# 示例用法
swordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
s = "pineapplepenapple"
print(wordBreak(s, swordDict))  # 应该返回 True

 300. 最长递增子序列 - 力扣(LeetCode)

最长递增子序列:可以不连续但是前后相对顺序不变

def lengthOfLIS(nums):if not nums:return 0# 初始化一个数组 dp,长度与输入数组相同,所有元素初始为 1# dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度dp = [1] * len(nums)# 遍历数组,计算每个位置的最长递增子序列长度for i in range(1, len(nums)):for j in range(i):# 如果当前元素 nums[i] 大于之前的元素 nums[j]# 并且以 nums[i] 结尾的子序列长度可以增加if nums[i] > nums[j]:dp[i] = max(dp[i], dp[j] + 1)# 返回 dp 数组中的最大值,即为最长递增子序列的长度return max(dp)# 示例用法
nums = [10, 9, 2, 5, 3, 7, 101, 18]
print(lengthOfLIS(nums))  # 输出应该是 4,因为最长递增子序列是 [2, 3, 7, 101]

重点:如果 nums[i] 大于 nums[j],那么我们可以将 nums[i] 添加到以 nums[j] 结尾的递增子序列中,从而形成一个更长的递增子序列。 

152. 乘积最大子数组 - 力扣(LeetCode)

最大乘积子数组问题是指在一个整数数组中找到一个连续的子数组(至少包含一个数),使得这个子数组中所有数的乘积是最大的。

tmp = imax;
imax = imin;
imin = tmp;
def maxProduct(nums):# 初始化最大乘积、当前最大乘积和当前最小乘积max_so_far = nums[0]min_so_far = nums[0]result = nums[0]# 遍历数组,从第二个元素开始for i in range(1, len(nums)):# 如果当前元素是负数,那么最大乘积和最小乘积会交换if nums[i] < 0:max_so_far, min_so_far = min_so_far, max_so_far# 更新当前最大乘积和最小乘积max_so_far = max(nums[i], max_so_far * nums[i])min_so_far = min(nums[i], min_so_far * nums[i])# 更新结果为最大乘积result = max(result, max_so_far)return result# 示例
nums = [2, 3, -2, 4]
print(maxProduct(nums))  # 输出: 6

416. 分割等和子集 - 力扣(LeetCode)

给定一个整数数组 ,如果您可以将数组划分为两个子集,使得两个子集中的元素之和相等,则 返回。

01背包问题

def canPartition(nums):total_sum = sum(nums)# 如果总和是奇数,直接返回 Falseif total_sum % 2 != 0:return Falsetarget = total_sum // 2dp = [False] * (target + 1)dp[0] = True  # 0 总是可以达成,不选择任何元素即可# 遍历所有物品(数组中的数字)for num in nums:# 这里必须从 target 递减到 num,以防止一个物品被重复使用for j in range(target, num - 1, -1):# 如果 dp[j - num] 是 True,则 dp[j] 也应该是 Truedp[j] = dp[j] or dp[j - num]# dp[target] 表示是否可以从数组中选取一些数字,使得这些数字的总和等于 targetreturn dp[target]# 示例
nums = [1, 5, 11, 5]
print(canPartition(nums))  # 输出: True

32. 最长有效括号 - 力扣(LeetCode)

当前字符是 ) 并且前一个字符是 (,当前字符是 ) 并且前一个字符也是 ):s = "()(())"

def longest_valid_parentheses(s):n = len(s)if n == 0:return 0# dp[i] 表示以 s[i] 结尾的最长有效括号的长度dp = [0] * nmax_len = 0for i in range(1, n):if s[i] == ')':# 如果前一个字符是'(',则可以形成一个有效的括号对if s[i - 1] == '(':dp[i] = (dp[i - 2] if i >= 2 else 0) + 2# 如果前一个字符是')',并且前面的有效括号长度为 dp[i - 1]# 并且 dp[i - 1] 前面的字符是'(',则可以扩展有效括号长度elif i - dp[i - 1] > 0 and s[i - dp[i - 1] - 1] == '(':dp[i] = dp[i - 1] + (dp[i - dp[i - 1] - 2] if i - dp[i - 1] >= 2 else 0) + 2max_len = max(max_len, dp[i])return max_len# 示例
print(longest_valid_parentheses("(()"))  # 输出 2
print(longest_valid_parentheses(")()())"))  # 输出 4

多维动态规划

62. 不同路径 - 力扣(LeetCode)

与杨辉三角和爬楼梯类似

空间复杂度:2n

class Solution:def uniquePaths(self, m: int, n: int) -> int:pre = [1] * ncur = [1] * nfor i in range(1, m):for j in range(1, n):cur[j] = pre[j] + cur[j-1]pre = cur[:]return pre[-1]

64. 最小路径和 - 力扣(LeetCode)

向下或向右移动从左上角到右下角的最小路径和

到达每个单元格 (i, j) 的最小路径和可以由到达其上方单元格 (i-1, j) 和左方单元格 (i, j-1) 的最小路径和推导出来。

 dp[i][j] 表示到达单元格 (i, j) 的最小路径和,到达 (i, j) 的最小路径和等于到达其上方和左方单元格的最小路径和中的较小者,再加上当前单元格的值。

def min_path_sum(grid):if not grid or not grid[0]:return 0m, n = len(grid), len(grid[0])dp = [[0] * n for _ in range(m)]# 初始化左上角dp[0][0] = grid[0][0]# 初始化第一列for i in range(1, m):dp[i][0] = dp[i - 1][0] + grid[i][0]# 初始化第一行for j in range(1, n):dp[0][j] = dp[0][j - 1] + grid[0][j]# 填充dp数组剩余部分for i in range(1, m):for j in range(1, n):# dp[i][j]可以从上方(dp[i-1][j])或左方(dp[i][j-1])到达,# 所以我们取两者的最小值,并加上当前格子的值。dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]# 右下角的格子将包含从左上角到右下角的最小路径和return dp[m - 1][n - 1]

5. 最长回文子串 - 力扣(LeetCode)

记录字符串中每对字符之间是否形成回文子串

def longest_palindromic_substring(s):n = len(s)if n == 0:return ""# 初始化一个二维数组,用于存储子串是否为回文dp = [[False] * n for _ in range(n)]start = 0  # 最长回文子串的起始位置max_length = 1  # 最长回文子串的长度# 所有长度为1的子串都是回文for i in range(n):dp[i][i] = True# 检查长度为2的子串是否为回文for i in range(n - 1):if s[i] == s[i + 1]:dp[i][i + 1] = Truestart = imax_length = 2# 检查长度大于2的子串for length in range(3, n + 1):  # 子串长度从3开始递增for i in range(n - length + 1):j = i + length - 1  # 子串的结束位置# 检查子串s[i:j+1]是否为回文if s[i] == s[j] and dp[i + 1][j - 1]:dp[i][j] = Truestart = imax_length = length# 返回最长回文子串return s[start:start + max_length]# 示例使用
s = "babad"
print(longest_palindromic_substring(s))  # 输出可能是"bab"或"aba"

1143. 最长公共子序列 - 力扣(LeetCode)

子序列可以是不连续的;子数组(子字符串)需要是连续的。

def longest_common_subsequence(text1, text2):# 获取两个字符串的长度m, n = len(text1), len(text2)# 初始化一个二维数组 dp,用于存储子问题的解# dp[i][j] 表示 text1 的前 i 个字符和 text2 的前 j 个字符的最长公共子序列的长度dp = [[0] * (n + 1) for _ in range(m + 1)]# 填充 dp 数组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], dp[i - 1][j - 1])# dp[m][n] 即为两个字符串的最长公共子序列的长度return dp[m][n]# 测试用例
text1 = "abcde"
text2 = "ace"
# 测试结果
print(longest_common_subsequence(text1, text2))  

72. 编辑距离 - 力扣(LeetCode)

定两个字符串 和 ,返回将 word1 转换为 word2 所需的最小步数

def minDistance(word1, word2):# 创建一个矩阵来存储子问题的解dp = [[0 for x in range(len(word2) + 1)] for x in range(len(word1) + 1)]# 初始化矩阵的第一行和第一列for i in range(len(word1) + 1):dp[i][0] = ifor j in range(len(word2) + 1):dp[0][j] = j# 填充dp矩阵for i in range(1, len(word1) + 1):for j in range(1, len(word2) + 1):# 如果当前字符相同,无需编辑,直接使用上一个状态的值if word1[i - 1] == word2[j - 1]:dp[i][j] = dp[i - 1][j - 1]else:# 如果字符不同,取插入、删除、替换三者的最小值加1dp[i][j] = 1 + min(dp[i - 1][j],    # 删除dp[i][j - 1],    # 插入dp[i - 1][j - 1] # 替换)# dp矩阵的最后一个元素即为编辑距离return dp[len(word1)][len(word2)]# 示例使用
word1 = "horse"
word2 = "ros"
print(minDistance(word1, word2))  # 输出应该是3,因为"horse" -> "ros"需要3步:h -> r, o ->

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

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

相关文章

本地Deepseek添加个人知识库(Page Assist/AnythingLLM)

本地Deepseek两种方法建立知识库 前言 &#xff08;及个人测试结论&#xff09;法一、在Page Assist建立知识库step1 下载nomic-embed-textstep2 加载进Page Assiststep3 添加知识step4 对话框添加知识库 法二、在AnythingLLM建立知识库准备工作1.下载nomic-embed-text2.下载An…

记8(高级API实现手写数字识别

目录 1、Keras&#xff1a;2、Sequential模型&#xff1a;2.1、建立Sequential模型&#xff1a;modeltf.keras.Sequential()2.2、添加层&#xff1a;model.add(tf.keras.layers.层)2.3、查看摘要&#xff1a;model.summary()2.4、配置训练方法&#xff1a;model.compile(loss,o…

grpc 和 http 的区别---二进制vsJSON编码

gRPC 和 HTTP 是两种广泛使用的通信协议&#xff0c;各自适用于不同的场景。以下是它们的详细对比与优势分析&#xff1a; 一、核心特性对比 特性gRPCHTTP协议基础基于 HTTP/2基于 HTTP/1.1 或 HTTP/2数据格式默认使用 Protobuf&#xff08;二进制&#xff09;通常使用 JSON/…

文字投影效果

大家好&#xff0c;我是喝西瓜汁的兔叽&#xff0c;今天给大家分享一个常见的文字投影效果。 效果展示 我们来实现一个这样的文字效果。 思路分析 这样的效果如何实现的呢? 实际上是两组相同的文字&#xff0c;叠合在一块&#xff0c;只不过对应的css不同罢了。 首先&…

图像处理之图像灰度化

目录 1 图像灰度化简介 2 图像灰度化处理方法 2.1 均值灰度化 2.2 经典灰度化 2.3 Photoshop灰度化 2.4 C语言代码实现 3 演示Demo 3.1 开发环境 3.2 功能介绍 3.3 下载地址 参考 1 图像灰度化简介 对于24位的RGB图像而言&#xff0c;每个像素用3字节表示&#xff0…

【课题推荐】基于t分布的非高斯滤波框架在水下自主导航中的应用研究

水下自主导航系统在海洋探测、环境监测及水下作业等领域具有广泛的应用。然而&#xff0c;复杂的水下环境常常导致传感器输出出现野值噪声&#xff0c;这些噪声会严重影响导航信息融合算法的精度&#xff0c;甚至导致系统发散。传统的卡尔曼滤波算法基于高斯噪声假设&#xff0…

知识库管理系统为企业赋能与数字化转型的关键解决方案分析

内容概要 在当今快速发展的商业环境中&#xff0c;知识库管理系统成为企业进行数字化转型的重要支撑工具。这类系统不仅可以帮助企业高效整合和管理其知识资产&#xff0c;还能提升信息共享与沟通的效率。通过科学的知识管理策略&#xff0c;企业可以在动态市场中实现精益管理…

HTML(快速入门)

欢迎大家来到我的博客~欢迎大家对我的博客提出指导&#xff0c;有错误的地方会改进的哦~点击这里了解更多内容 目录 一、前言二、HTML基础2.1 什么是HTML?2.2 认识HTML标签2.2.1 HTML标签当中的基本结构2.2.2 标签层次结构 2.3 HTML常见标签2.3.1 标题标签2.3.2 段落标签2.3.3…

vue入门到实战 二

目录 2.1 计算属性computed 2.1.1什么是计算属性 2.1.2 只有getter方法的计算属性 2.1.3 定义有getter和setter方法的计算属性 2.1.4 计算属性和methods的对比 2.2 监听器属性watch 2.2.1 watch属性的用法 2.2.2 computed属性和watch属性的对比 2.1 计算属性computed…

Python从0到100(八十六):神经网络-ShuffleNet通道混合轻量级网络的深入介绍

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

Baklib赋能企业实现高效数字化内容管理提升竞争力

内容概要 在数字经济的浪潮下&#xff0c;企业面临着前所未有的机遇与挑战。随着信息技术的迅猛发展&#xff0c;各行业都在加速推进数字化转型&#xff0c;以保持竞争力。在这个过程中&#xff0c;数字化内容管理成为不可或缺的一环。高效的内容管理不仅能够优化内部流程&…

六十分之三十七——一转眼、时光飞逝

一、目标 明确可落地&#xff0c;对于自身执行完成需要一定的努力才可以完成的 1.第三版分组、激励、立体化权限、智能设备、AIPPT做课 2.8本书 3.得到&#xff1a;头条、吴军来信2、卓克科技参考3 4.总结思考 二、计划 科学规律的&#xff0c;要结合番茄工作法、快速阅读、…

实验十 Servlet(一)

实验十 Servlet(一) 【实验目的】 1&#xff0e;了解Servlet运行原理 2&#xff0e;掌握Servlet实现方式 【实验内容】 1、参考课堂例子&#xff0c;客户端通过login.jsp发出登录请求&#xff0c;请求提交到loginServlet处理。如果用户名和密码相同则视为登录成功&#xff0c…

基于springboot+vue的哈利波特书影音互动科普网站

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

【python】四帧差法实现运动目标检测

四帧差法是一种运动目标检测技术&#xff0c;它通过比较连续四帧图像之间的差异来检测运动物体。这种方法可以在一定的程度上提高检测的准确性。 目录 1 方案 2 实践 ① 代码 ② 效果图 1 方案 具体的步骤如下&#xff1a; ① 读取视频流&#xff1a;使用cv2.VideoCapture…

Chapter2 Amplifiers, Source followers Cascodes

Chapter2 Amplifiers, Source followers & Cascodes MOS单管根据输入输出, 可分为CS放大器, source follower和cascode 三种结构. Single-transistor amplifiers 这一章学习模拟电路基本单元-单管放大器 单管运放由Common-Source加上DC电流源组成. Avgm*Rds, gm和rds和…

Linux系统上安装与配置 MySQL( CentOS 7 )

目录 1. 下载并安装 MySQL 官方 Yum Repository 2. 启动 MySQL 并查看运行状态 3. 找到 root 用户的初始密码 4. 修改 root 用户密码 5. 设置允许远程登录 6. 在云服务器配置 MySQL 端口 7. 关闭防火墙 8. 解决密码错误的问题 前言 在 Linux 服务器上安装并配置 MySQL …

14-9-2C++STL的set容器

&#xff08;一&#xff09;函数对象的基本概念 set容器的元素排序 1.set<int,less<int> >setlntA;//该容器是按升序方式排列元素&#xff0c;set<int>相当于set<int,less<int>> 2.set<int,greater<int> >setlntB;//该容器是按降序…

音视频入门基础:RTP专题(8)——使用Wireshark分析RTP

一、引言 通过Wireshark可以抓取RTP数据包&#xff0c;该软件可以从Wireshark Go Deep 下载。 二、通过Wireshark抓取RTP数据包 首先通过FFmpeg将一个媒体文件转推RTP&#xff0c;生成RTP流&#xff1a; ffmpeg -re -stream_loop -1 -i input.mp4 -vcodec copy -an -f rtp …

解决whisper 本地运行时GPU 利用率不高的问题

我在windows 环境下本地运行whisper 模型&#xff0c;使用的是nivdia RTX4070 显卡&#xff0c;结果发现GPU 的利用率只有2% 。使用 import torch print(torch.cuda.is_available()) 返回TRUE。表示我的cuda 是可用的。 最后在github 的下列网页上找到了问题 极低的 GPU 利…