代码随想录算法训练营第十九天 | 动态规划系列5,6,7,8
发布人:shili8
发布时间:2024-12-26 14:34
阅读次数:0
**代码随想录算法训练营第十九天**
**动态规划系列5-8**
在前面的几篇文章中,我们已经学习了动态规划的基本概念、应用场景以及几个经典问题的解决方案。今天,我们将继续深入探讨动态规划的主题,重点介绍四个新的问题:最长上升子序列(Longest Increasing Subsequence, LIS)、最短路径和最长路径(Shortest Path and Longest Path)、背包问题(Knapsack Problem)以及最小割(Minimum Cut)。
### 最长上升子序列(LIS)
**问题描述**
给定一个整数数组 `arr`,要求找到其中的最长上升子序列(LIS)。也就是说,我们需要从原数组中找出一段连续的子序列,使得每两个相邻元素都满足递增关系。
**动态规划解决方案**
我们可以使用一个长度为 `n` 的数组 `dp` 来表示最长上升子序列的长度,其中 `n` 是原数组的大小。对于每个位置 `i`,我们需要找到从 `arr[0]` 到 `arr[i-1]` 中能组成的最长上升子序列的长度,并将其存储在 `dp[i]` 中。
def longest_increasing_subsequence(arr): n = len(arr) dp = [1] * n # 初始化dp数组 for i in range(1, n): for j in range(i): if arr[i] > arr[j]: dp[i] = max(dp[i], dp[j] +1) return max(dp) # 返回最长上升子序列的长度
**时间复杂度分析**
该算法的时间复杂度为 O(n^2),因为我们需要对每个位置 `i` 进行 O(n) 次比较。
### 最短路径和最长路径**问题描述**
给定一个有向图 `graph`,要求找到从源点到目标点的最短路径长度和最长路径长度。
**动态规划解决方案**
我们可以使用两个长度为 `n` 的数组 `dp_shortest` 和 `dp_longest` 来表示最短路径长度和最长路径长度,其中 `n` 是图中顶点的数量。对于每个位置 `i`,我们需要找到从源点到 `i` 的最短路径长度和最长路径长度,并将其存储在 `dp_shortest[i]` 和 `dp_longest[i]` 中。
def shortest_and_longest_path(graph): n = len(graph) dp_shortest = [float('inf')] * n # 初始化dp_shortest数组 dp_longest = [0] * n # 初始化dp_longest数组 dp_shortest[0] =0 # 源点的最短路径长度为0 dp_longest[0] =0 # 源点的最长路径长度为0 for i in range(1, n): for j in range(i): if graph[i][j] != float('inf'): dp_shortest[i] = min(dp_shortest[i], dp_shortest[j] + graph[i][j]) dp_longest[i] = max(dp_longest[i], dp_longest[j] + graph[i][j]) return dp_shortest[-1], dp_longest[-1] # 返回最短路径长度和最长路径长度
**时间复杂度分析**
该算法的时间复杂度为 O(n^2),因为我们需要对每个位置 `i` 进行 O(n) 次比较。
### 背包问题**问题描述**
给定一个物品集合 `items`,要求找到能装入背包中最多价值的子集,并且背包的容量为 `capacity`。
**动态规划解决方案**
我们可以使用一个长度为 `n+1` 的数组 `dp` 来表示能装入背包中最多价值的子集,其中 `n` 是物品集合的大小。对于每个位置 `i`,我们需要找到从 `items[0]` 到 `items[i-1]` 中能组成的最多价值的子集,并将其存储在 `dp[i]` 中。
def knapsack(items, capacity): n = len(items) dp = [0] * (n +1) # 初始化dp数组 for i in range(1, n +1): for j in range(capacity +1): if items[i -1][0] <= j: dp[i] = max(dp[i], dp[i -1]) dp[i] = max(dp[i], dp[i -1] + items[i -1][1]) return dp[-1] # 返回能装入背包中最多价值的子集
**时间复杂度分析**
该算法的时间复杂度为 O(n*capacity),因为我们需要对每个位置 `i` 进行 O(capacity) 次比较。
### 最小割**问题描述**
给定一个有向图 `graph`,要求找到最小割的大小。
**动态规划解决方案**
我们可以使用两个长度为 `n+1` 的数组 `dp_mincut` 和 `dp_maxflow` 来表示最小割的大小和最大流的大小,其中 `n` 是图中顶点的数量。对于每个位置 `i`,我们需要找到从源点到 `i` 的最小割的大小和最大流的大小,并将其存储在 `dp_mincut[i]` 和 `dp_maxflow[i]` 中。
def min_cut(graph): n = len(graph) dp_mincut = [float('inf')] * (n +1) # 初始化dp_mincut数组 dp_maxflow = [0] * (n +1) # 初始化dp_maxflow数组 dp_mincut[0] =0 # 源点的最小割大小为0 dp_maxflow[0] =0 # 源点的最大流大小为0 for i in range(1, n +1): for j in range(i): if graph[i][j] != float('inf'): dp_mincut[i] = min(dp_mincut[i], dp_mincut[j] + graph[i][j]) dp_maxflow[i] = max(dp_maxflow[i], dp_maxflow[j] + graph[i][j]) return dp_mincut[-1] # 返回最小割的大小
**时间复杂度分析**
该算法的时间复杂度为 O(n^2),因为我们需要对每个位置 `i` 进行 O(n) 次比较。
以上就是本文关于动态规划系列5-8的内容。这些问题都是经典的动态规划问题,通过使用动态规划,我们可以有效地解决这些问题,并且得到最优解。