当前位置:
首页>
汽车>
新车 > 海外网站服务器租用_代驾小程序定制开发_杭州百度推广开户_太原整站优化排名外包
海外网站服务器租用_代驾小程序定制开发_杭州百度推广开户_太原整站优化排名外包
时间:2025/7/13 11:32:32来源:https://blog.csdn.net/weixin_45880844/article/details/146973953 浏览次数: 0次
海外网站服务器租用_代驾小程序定制开发_杭州百度推广开户_太原整站优化排名外包
目录
- 考虑用动态规划的情况
- 动态规划的时间复杂度
- 使用动态规划解决问题时需要关注
- 经典使用动态规划解决问题的案例
- 经典0-1背包问题
- 最长公共子序列
- 最长连续子序列
- 最长递增子序列
- 最长连续递增子序列
- 回文子串的数量
- 最长的回文子串
考虑用动态规划的情况
- 一个问题如果具有重叠子问题和最优子结构特征,那么初步考虑可以使用动态规划。
- 重叠子问题:在递归求解过程中,相同的子问题被多次计算。
- 最优子结构:问题的最优解可以由其子问题的最优解组合而成。
动态规划的时间复杂度
- 动态规划的时间复杂度通常取决于状态的数量和状态转移的复杂度。
使用动态规划解决问题时需要关注
- 状态定义:
dp
数组的含义。 - 状态转移方程:既然最优解会依赖于子问题的最优解,那么具体是怎么依赖的。
- 初始化:确定动态规划表的初始值。这通常取决于问题的具体情况,例如,对于最长递增子序列问题,每个元素的初始值为
1
,因为每个元素本身可以看作一个长度为1
的递增子序列。 - 边界条件:确定问题的边界条件,即在哪些情况下可以直接得出结果,不需要进一步的计算。例如,在
0-1
背包问题中,如果背包容量为0
,或者物品数量为0
,那么最大价值显然为0
。 - 遍历顺序:确定遍历的顺序,以保证在计算某个状态时,其依赖的所有状态都已经被计算。例如,在
0-1
背包问题中,通常先遍历物品,再遍历背包容量;而在最长递增子序列问题中,通常从左到右遍历序列。 - 时间复杂度:很多时候使用动态规划解决问题时,是方便了理解解决思路,但是不一定时间复杂度就也很低。
经典使用动态规划解决问题的案例
经典0-1背包问题
- 问题描述:给定一组物品,每个物品有对应的价值和重量。同时给定一个背包,背包的最大承重能力为
capacity
。目标是在不超过背包容量的前提下,选择物品放入背包,使得背包中物品的总价值最大化。 - 状态定义:
dp[i][j]
表示考虑前i
个物品,在容量为j
的背包下能获得的最大价值。 - 状态转移方程:
- 如果不选择第
i
个物品:dp[i][j] = dp[i-1][j]
- 如果选择第
i
个物品:dp[i][j] = dp[i-1][j - w[i]] + v[i]
(前提是j >= w[i]
)
- 时间复杂度:
O(n * W)
,其中n
是物品数量,W
是背包容量。 - 代码实现:
def knapsack(values, weights, capacity):"""0-1背包问题:param values: 物品的价值列表:param weights: 物品的重量列表:param capacity: 背包的最大容量:return: 最大价值"""n = len(values)dp = [[0] * (capacity + 1) for _ in range(n + 1)]for i in range(1, n + 1): for j in range(1, capacity + 1): if weights[i - 1] <= j: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])else:dp[i][j] = dp[i - 1][j]return dp[n][capacity]
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
print(knapsack(values, weights, capacity))
最长公共子序列
- 问题描述:给定两个字符串
seq1
和seq2
,目标是找到它们的最长公共子序列的长度。公共子序列是指在两个字符串中都出现的子序列,但不要求这些字符在原字符串中是连续的。 - 状态定义:
dp[i][j]
表示第一个序列的前i
个字符和第二个序列的前j
个字符的最长公共子序列的长度。 - 状态转移方程:
- 如果
seq1[i-1] == seq2[j-1]
,则dp[i][j] = dp[i-1][j-1] + 1
- 否则,
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
- 时间复杂度:
O(m * n)
,其中m
和n
分别是两个序列的长度。 - 代码实现:
def longest_common_subsequence(seq1, seq2):"""最长公共子序列:param seq1: 第一个序列:param seq2: 第二个序列:return: 最长公共子序列的长度"""m, n = len(seq1), len(seq2)dp = [[0] * (n + 1) for _ in range(m + 1)]for i in range(1, m + 1):for j in range(1, n + 1):if seq1[i - 1] == seq2[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]
seq1 = "ABCBDAB"
seq2 = "BDCABC"
print(longest_common_subsequence(seq1, seq2))
最长连续子序列
- 问题描述:给定一个整数序列
nums
,目标是找到其中最长的连续子序列的长度。这里的“连续”指的是数值上的连续,例如[1, 2, 3, 4]
是一个长度为4
的连续子序列。 - 状态定义:
dp[i]
表示以第i
个元素结尾的最长连续子序列的长度。 - 状态转移方程:
- 如果
nums[i] == nums[i-1] + 1
,则dp[i] = dp[i-1] + 1
- 否则,
dp[i] = 1
- 时间复杂度:
O(n)
,其中n
是序列长度。 - 代码实现:
def longest_consecutive_subsequence(nums):"""最长连续子序列:param nums: 数字序列:return: 最长连续子序列的长度"""if not nums:return 0nums.sort()n = len(nums)dp = [1] * nfor i in range(1, n):if nums[i] == nums[i - 1] + 1: dp[i] = dp[i - 1] + 1return max(dp)
nums = [100, 4, 200, 1, 3, 2]
print(longest_consecutive_subsequence(nums))
最长递增子序列
- 问题描述:给定一个整数序列
nums
,目标是找到其中最长的递增子序列的长度。递增子序列是指子序列中的元素是严格递增的,但不要求这些元素在原序列中是连续的。 - 状态定义:
dp[i]
表示以第i
个元素结尾的最长递增子序列的长度。 - 状态转移方程:
- 对于每个
j < i
,如果nums[j] < nums[i]
,则dp[i] = max(dp[i], dp[j] + 1)
- 时间复杂度:
O(n^2)
,其中n
是序列长度。如果使用二分查找优化,时间复杂度可以降低到O(n log n)
。 - 代码实现:
def longest_increasing_subsequence(nums):"""最长递增子序列:param nums: 数字序列:return: 最长递增子序列的长度"""if not nums:return 0n = len(nums)dp = [1] * nfor i in range(1, n):for j in range(i):if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1)return max(dp)
nums = [10, 9, 2, 5, 3, 7, 101, 18]
print(longest_increasing_subsequence(nums))
最长连续递增子序列
- 问题描述:给定一个整数序列
nums
,目标是找到其中最长的连续递增子序列的长度。这里的“连续”指的是数值上的连续,且子序列中的元素在原序列中也是连续的。 - 状态定义:
dp[i]
表示以第i
个元素结尾的最长连续递增子序列的长度。 - 状态转移方程:
- 如果
nums[i] > nums[i-1]
,则dp[i] = dp[i-1] + 1
。 - 否则,
dp[i] = 1
(即从当前元素重新开始一个新的连续递增子序列)。
- 时间复杂度:
O(n)
,其中n
是数组的长度。只需要遍历一次数组即可完成状态转移。 - 代码实现:
def longest_continuous_increasing_subsequence(nums):"""最长连续递增子序列:param nums: 数字序列:return: 最长连续递增子序列的长度"""if not nums:return 0n = len(nums)dp = [1] * nfor i in range(1, n):if nums[i] > nums[i - 1]: dp[i] = dp[i - 1] + 1 else:dp[i] = 1 return max(dp)
nums = [1, 3, 5, 4, 7]
print(longest_continuous_increasing_subsequence(nums)) nums = [2, 2, 2, 2, 2]
print(longest_continuous_increasing_subsequence(nums))
回文子串的数量
- 问题描述:给定一个字符串
s
,目标是统计其中回文子串的数量。回文子串是指正读和反读都相同的子串。 - 状态定义:
dp[i][j]
:布尔值,表示子串s[i..j]
是否是回文。 - 状态转移方程:
- 当
s[i] == s[j]
:如果j - i <= 1
,即子串长度为1
或2
,直接判断为回文。 - 当
s[i] == s[j]
:如果j - i > 1
,则需要检查dp[i + 1][j - 1]
是否为回文。
- 时间复杂度:
O(n²)
,其中n
是字符串的长度。 - 代码实现:
def countSubstrings(s):n = len(s)if n == 0:return 0dp = [[False] * n for _ in range(n)]count = 0for i in range(n):dp[i][i] = Truecount += 1for i in range(n - 1):if s[i] == s[i + 1]:dp[i][i + 1] = Truecount += 1for length in range(3, n + 1): for i in range(n - length + 1): j = i + length - 1 if s[i] == s[j] and dp[i + 1][j - 1]:dp[i][j] = Truecount += 1return count
s = "abc"
print(countSubstrings(s)) s = "aaa"
print(countSubstrings(s))
最长的回文子串
- 问题描述:给定一个字符串s,目标是找到其中最长的回文子串。回文是指正读和反读相同的字符串。
- 状态定义:
dp[i][j]
:布尔值,表示子串s[i..j]
是否是回文。 - 状态转移方程:
- 如果
s[i] == s[j]
,且dp[i+1][j-1]
为True
,则dp[i][j] = True
。 - 否则,
dp[i][j] = False
。
- 时间复杂度:
O(n²)
,其中n
是字符串的长度。 - 代码实现:
def longestPalindrome_dp(s):n = len(s)if n < 2:return sdp = [[False] * n for _ in range(n)]start, max_len = 0, 1for i in range(n):dp[i][i] = Truefor i in range(n - 1):if s[i] == s[i + 1]:dp[i][i + 1] = Truestart = imax_len = 2for length in range(3, n + 1): for i in range(n - length + 1): j = i + length - 1 if s[i] == s[j] and dp[i + 1][j - 1]:dp[i][j] = Truestart = imax_len = lengthreturn s[start:start + max_len]
s = "babad"
print(longestPalindrome_dp(s))
关键字:海外网站服务器租用_代驾小程序定制开发_杭州百度推广开户_太原整站优化排名外包
版权声明:
本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。
我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com
责任编辑: