509.斐波那契数
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
1 2
| F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1
|
1 2 3
| 输入:n = 2 输出:1 解释:F(2) = F(1) + F(0) = 1 + 0 = 1
|
示例 2:
1 2 3
| 输入:n = 3 输出:2 解释:F(3) = F(2) + F(1) = 1 + 1 = 2
|
示例 3:
1 2 3
| 输入:n = 4 输出:3 解释:F(4) = F(3) + F(2) = 2 + 1 = 3
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution: def fib( n: int) -> int:
if n==0: return None dp=[0]*(n+1) dp[0]=0 dp[1]=1 for i in range(2,n+1): dp[i]=dp[i-1]+dp[i-2] return dp[n]
|
70.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
1 2 3 4 5
| 输入:n = 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 + 1 阶 2. 2 阶
|
示例 2:
1 2 3 4 5 6
| 输入:n = 3 输出:3 解释:有三种方法可以爬到楼顶。 1. 1 阶 + 1 阶 + 1 阶 2. 1 阶 + 2 阶 3. 2 阶 + 1 阶
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution: def climbStairs(n: int) -> int: if n==0: return 0 dp=[0]*(n) dp[0]=1 dp[1]=2 for i in range(2,n): dp[i]=dp[i-1]+dp[i-2] return dp[n-1]
|
746.使用最小花费爬楼梯
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
示例 1:
1 2 3 4 5
| 输入:cost = [10,15,20] 输出:15 解释:你将从下标为 1 的台阶开始。 - 支付 15 ,向上爬两个台阶,到达楼梯顶部。 总花费为 15 。
|
示例 2:
1 2 3 4 5 6 7 8 9 10
| 输入:cost = [1,100,1,1,1,100,1,1,100,1] 输出:6 解释:你将从下标为 0 的台阶开始。 - 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。 - 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。 - 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。 - 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。 - 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。 - 支付 1 ,向上爬一个台阶,到达楼梯顶部。 总花费为 6 。
|
代码:
1 2 3 4 5 6 7 8 9
| class Solution: def minCostClimbingStairs(cost) : n=len(cost) dp=[0]*(n+1) for i in range(2,n+1): dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]) return dp[-1]
|
62.不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:

示例 2:
1 2 3 4 5 6 7
| 输入:m = 3, n = 2 输出:3 解释: 从左上角开始,总共有 3 条路径可以到达右下角。 1. 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 3. 向下 -> 向右 -> 向下
|
示例 3:
示例 4:
代码:
1 2 3 4 5 6 7 8 9
| class Solution: def uniquePaths( m: int, n: int) -> int: dp=[[1 for i in range(n)]for j in range(m)] for i in range(1,m): for j in range(1,n): dp[i][j]=dp[i-1][j]+dp[i][j-1] return dp[m-1][n-1]
|
63.不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:

1 2 3 4 5 6
| 输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] 输出:2 解释:3x3 网格的正中间有一个障碍物。 从左上角到右下角一共有 2 条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 -> 向右
|
示例 2:

1 2
| 输入:obstacleGrid = [[0,1],[0,0]] 输出:1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution: def uniquePathsWithObstacles(self, obstacleGrid): row=len(obstacleGrid) col=len(obstacleGrid[0]) dp=[[0 for i in range(col)]for j in range(row)] dp[0][0]=0 if obstacleGrid[0][0]==1 else 1 if dp[0][0]==0: return 0 for i in range(len(col)): if obstacleGrid[0][i]==1: break dp[0][i]=1 for j in range(len(row)): if obstacleGrid[j][0]==1: break dp[j][0]=1 for i in range(1,row): for j in range(1,col): if obstacleGrid[i][j]==0: dp[i][j]=dp[i-1][j]+dp[i][j-1] return dp[-1][-1]
|
343.整数拆分
给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。
返回 你可以获得的最大乘积 。
示例 1:
1 2 3
| 输入: n = 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1。
|
示例 2:
1 2 3
| 输入: n = 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
|
代码:
1 2 3 4 5 6 7 8 9 10 11
| class Solution: def integerBreak(n): dp = [0] * (n + 1) dp[2] = 1 for i in range(3, n + 1): for j in range(1, i / 2 + 1): dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j])) return dp[n]
|
96.不同的二叉搜索树
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1:

示例 2:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution: def numTrees(self, n: int) -> int: dp = [0] * (n + 1) dp[0], dp[1] = 1, 1 for i in range(2, n + 1): for j in range(1, i + 1): dp[i] += dp[j - 1] * dp[i - j] return dp[-1]
|
01 背包
有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| def test_2_wei_bag_problem1(bag_size, weight, value): rows, cols = len(weight), bag_size + 1 dp = [[0 for _ in range(cols)] for _ in range(rows)] for i in range(rows): dp[i][0] = 0 first_item_weight, first_item_value = weight[0], value[0] for j in range(1, cols): if first_item_weight <= j: dp[0][j] = first_item_value for i in range(1, len(weight)): cur_weight, cur_val = weight[i], value[i] for j in range(1, cols): if cur_weight > j: dp[i][j] = dp[i - 1][j] else: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight]+ cur_val)
|
416.分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
1 2 3
| 输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
|
示例 2:
1 2 3
| 输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割成两个元素和相等的子集。
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
class Solution: def canPartition(self, nums): target = sum(nums) nums = sorted(nums) if target % 2 != 0: return False target = target // 2 row = len(nums) col = target + 1
dp = [[0 for _ in range(col)] for _ in range(row)]
for i in range(row): dp[i][0] = 0 for j in range(1, target): if nums[0] <= j: dp[0][j] = nums[0]
for i in range(1, row): cur_weight = nums[i] cur_value = nums[i] for j in range(1, col): if cur_weight > j: dp[i][j] = dp[i - 1][j] else: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight] + cur_value)
return dp[-1][col - 1] == target
|
1049.最后一块石头的重量 II
有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
- 如果
x == y,那么两块石头都会被完全粉碎;
- 如果
x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。
示例 1:
1 2 3 4 5 6 7
| 输入:stones = [2,7,4,1,8,1] 输出:1 解释: 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1], 组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1], 组合 2 和 1,得到 1,所以数组转化为 [1,1,1], 组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
|
示例 2:
1 2
| 输入:stones = [31,26,33,21,40] 输出:5
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution(object): def lastStoneWeightII(self, stones): """ :type stones: List[int] :rtype: int """ total_sum = sum(stones) target = total_sum // 2
dp = [[0] * (target + 1) for _ in range(len(stones))]
for j in range(1, target+1): if stones[0] <= j: dp[0][j] = stones[0]
for i in range(1, len(stones)): for j in range(1, target + 1): if stones[i] > j: dp[i][j] = dp[i - 1][j] else: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - stones[i]]+stones[i]) return total_sum - 2 * dp[-1][-1]
|
494.目标和
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :
- 例如,
nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
示例 1:
1 2 3 4 5 6 7 8
| 输入:nums = [1,1,1,1,1], target = 3 输出:5 解释:一共有 5 种方法让最终目标和为 3 。 -1 + 1 + 1 + 1 + 1 = 3 +1 - 1 + 1 + 1 + 1 = 3 +1 + 1 - 1 + 1 + 1 = 3 +1 + 1 + 1 - 1 + 1 = 3 +1 + 1 + 1 + 1 - 1 = 3
|
示例 2:
1 2
| 输入:nums = [1], target = 1 输出:1
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
class Solution: def findTargetSumWays(self, nums, target: int) -> int: total_sum = sum(nums) if abs(target) > total_sum: return 0 if (target + total_sum) % 2 == 1: return 0 target_sum = (target + total_sum) // 2 dp = [[0] * (target_sum + 1) for _ in range(len(nums) + 1)]
dp[0][0] = 1
for i in range(1, len(nums) + 1): for j in range(target_sum + 1): dp[i][j] = dp[i - 1][j] if j >= nums[i - 1]: dp[i][j] += dp[i - 1][j - nums[i - 1]]
return dp[len(nums)][target_sum]
|
474.一和零
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
示例 1:
1 2 3 4
| 输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3 输出:4 解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。
|
示例 2:
1 2 3
| 输入:strs = ["10", "0", "1"], m = 1, n = 1 输出:2 解释:最大的子集是 {"0", "1"} ,所以答案是 2
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution: def findMaxForm(strs, m: int, n: int) -> int: dp = [[0] * (n + 1) for _ in range(m + 1)] for s in strs: ones = s.count('1') zeros = s.count('0') for i in range(m, zeros - 1, -1): for j in range(n, ones - 1, -1): dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) return dp[m][n]
|
518.零钱兑换 II
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
示例 1:
1 2 3 4 5 6 7
| 输入:amount = 5, coins = [1, 2, 5] 输出:4 解释:有四种方式可以凑成总金额: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1
|
示例 2:
1 2 3
| 输入:amount = 3, coins = [2] 输出:0 解释:只用面额 2 的硬币不能凑成总金额 3 。
|
示例 3:
1 2
| 输入:amount = 10, coins = [10] 输出:1
|
代码:
1 2 3 4 5 6 7 8 9 10 11
| class Solution: def change( amount: int, coins) -> int: dp = [0]*(amount + 1) dp[0] = 1 for i in range(len(coins)): for j in range(coins[i], amount + 1): dp[j] += dp[j - coins[i]] return dp[amount]
|
377.组合总和 Ⅳ
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12
| 输入:nums = [1,2,3], target = 4 输出:7 解释: 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序不同的序列被视作不同的组合。
|
示例 2:
1 2
| 输入:nums = [9], target = 3 输出:0
|
代码:
跟上一题代码一样
322.零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例 1:
1 2 3
| 输入:coins = [1, 2, 5], amount = 11 输出:3 解释:11 = 5 + 5 + 1
|
示例 2:
1 2
| 输入:coins = [2], amount = 3 输出:-1
|
示例 3:
1 2
| 输入:coins = [1], amount = 0 输出:0
|
代码:
1 2 3 4 5 6 7 8 9 10 11
| class Solution: def coinChange(self, coins: List[int], amount: int) -> int: dp = [float('inf')] * (amount + 1) dp[0] = 0
for coin in coins: for i in range(coin, amount + 1): dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
|
279.完全平方数
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
1 2 3
| 输入:n = 12 输出:3 解释:12 = 4 + 4 + 4
|
示例 2:
1 2 3
| 输入:n = 13 输出:2 解释:13 = 4 + 9
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution: def numSquares(self, n: int) -> int: dp = [float('inf')] * (n + 1) dp[0] = 0 for i in range(1, int(n ** 0.5) + 1): for j in range(i * i, n + 1): dp[j] = min(dp[j - i * i] + 1, dp[j])
return dp[n]
|
139.单词拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例 1:
1 2 3
| 输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
|
示例 2:
1 2 3 4
| 输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。 注意,你可以重复使用字典中的单词。
|
示例 3:
1 2
| 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
|
1 2 3 4 5 6 7 8 9 10 11
| class Solution: def wordBreak(self, s: str, wordDict: List[str]) -> bool: dp = [False]*(len(s) + 1) dp[0] = True for j in range(1, len(s) + 1): for word in wordDict: if j >= len(word): dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j]) return dp[len(s)]
|
121.买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
1 2 3 4
| 输入:[7,1,5,3,6,4] 输出:5 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
|
示例 2:
1 2 3
| 输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
|
思路:
- 确定递推公式
如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来
- 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
- 第i天买入股票,所得现金就是买入今天的股票后所得现金即:-prices[i]
那么dp[i][0]应该选所得现金最大的,所以dp[i][0] = max(dp[i - 1][0], -prices[i]);
如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来
- 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
- 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金即:prices[i] + dp[i - 1][0]
同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
代码:
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution: def maxProfit(self, prices: List[int]) -> int: length = len(prices) if len == 0: return 0 dp = [[0] * 2 for _ in range(length)] dp[0][0] = -prices[0] dp[0][1] = 0 for i in range(1, length): dp[i][0] = max(dp[i-1][0], -prices[i]) dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0]) return dp[-1][1]
|
122.买卖股票的最佳时机 II
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
1 2 3 4 5
| 输入:prices = [7,1,5,3,6,4] 输出:7 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。 总利润为 4 + 3 = 7 。
|
示例 2:
1 2 3 4
| 输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 总利润为 4 。
|
示例 3:
1 2 3
| 输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution: def maxProfit(self, prices: List[int]) -> int: length = len(prices) dp = [[0] * 2 for _ in range(length)] dp[0][0] = -prices[0] dp[0][1] = 0 for i in range(1, length): dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]) return dp[-1][1]
|
123.买卖股票的最佳时机 III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
1 2 3 4
| 输入:prices = [3,3,5,0,0,3,1,4] 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
|
示例 2:
1 2 3 4 5
| 输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
|
示例 3:
1 2 3
| 输入:prices = [7,6,4,3,1] 输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
|
示例 4:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Solution(object): def maxProfit(self, prices): dp = [[0]*5 for _ in range(len(prices))] dp[0][0] = 0 dp[0][1] = -prices[0] dp[0][2] = 0 dp[0][3] = -prices[0] dp[0][4] = 0
for i in range(1,len(prices)): dp[i][0] = dp[i-1][0] dp[i][1] = max(dp[i-1][1],dp[i-1][0]-prices[i]) dp[i][2] = max(dp[i-1][2],dp[i-1][1]+prices[i]) dp[i][3] = max(dp[i-1][3],dp[i-1][2]-prices[i]) dp[i][4] = max(dp[i-1][4],dp[i-1][3]+prices[i]) return dp[-1][4]
|
188.买卖股票的最佳时机 IV
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格,和一个整型 k 。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
1 2 3
| 输入:k = 2, prices = [2,4,1] 输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
|
示例 2:
1 2 3 4
| 输入:k = 2, prices = [3,2,6,5,0,3] 输出:7 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。 随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution: def maxProfit(self, k: int, prices: List[int]) -> int: if len(prices) == 0: return 0 dp = [[0] * (2*k+1) for _ in range(len(prices))] for j in range(1, 2*k, 2): dp[0][j] = -prices[0] for i in range(1, len(prices)): for j in range(0, 2*k-1, 2): dp[i][j+1] = max(dp[i-1][j+1], dp[i-1][j] - prices[i]) dp[i][j+2] = max(dp[i-1][j+2], dp[i-1][j+1] + prices[i]) return dp[-1][2*k]
|
309.最佳买卖股票时机含冷冻期
给定一个整数数组prices,其中第 prices[i] 表示第 *i* 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
1 2 3
| 输入: prices = [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
|
示例 2:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) if n < 2: return 0
dp = [[0] * 3 for _ in range(n)] dp[0][0] = -prices[0] dp[0][1] = 0 dp[0][2] = 0
for i in range(1, n): dp[i][0] = max(dp[i-1][0], dp[i-1][2] - prices[i]) dp[i][1] = dp[i-1][0] + prices[i] dp[i][2] = max(dp[i-1][2], dp[i-1][1])
return max(dp[-1][1], dp[-1][2])
|
714.买卖股票的最佳时机含手续费
给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1:
1 2 3 4 5 6 7 8
| 输入:prices = [1, 3, 2, 8, 4, 9], fee = 2 输出:8 解释:能够达到的最大利润: 在此处买入 prices[0] = 1 在此处卖出 prices[3] = 8 在此处买入 prices[4] = 4 在此处卖出 prices[5] = 9 总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8
|
示例 2:
1 2
| 输入:prices = [1,3,7,5,10,3], fee = 3 输出:6
|
代码:
1 2 3 4 5 6 7 8 9
| class Solution: def maxProfit(self, prices: List[int], fee: int) -> int: n = len(prices) dp = [[0] * 2 for _ in range(n)] dp[0][0] = -prices[0] for i in range(1, n): dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee) return max(dp[-1][0], dp[-1][1])
|
300.最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
1 2 3
| 输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
|
示例 2:
1 2
| 输入:nums = [0,1,0,3,2,3] 输出:4
|
示例 3:
1 2
| 输入:nums = [7,7,7,7,7,7,7] 输出:1
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution: def lengthOfLIS(self, nums: List[int]) -> int: if len(nums) <= 1: return len(nums) dp = [1] * len(nums) result = 1 for i in range(1, len(nums)): for j in range(0, i): if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1) result = max(result, dp[i]) return result
|
674.最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。
示例 1:
1 2 3 4
| 输入:nums = [1,3,5,4,7] 输出:3 解释:最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
|
示例 2:
1 2 3
| 输入:nums = [2,2,2,2,2] 输出:1 解释:最长连续递增序列是 [2], 长度为1。
|
代码:
1 2 3 4 5 6 7 8 9 10 11
| class Solution: def findLengthOfLCIS(self, nums: List[int]) -> int: if len(nums) == 0: return 0 result = 1 dp = [1] * len(nums) for i in range(len(nums)-1): if nums[i+1] > nums[i]: dp[i+1] = dp[i] + 1 result = max(result, dp[i+1]) return result
|
718.最长重复子数组
给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。
示例 1:
1 2 3
| 输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] 输出:3 解释:长度最长的公共子数组是 [3,2,1] 。
|
示例 2:
1 2
| 输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0] 输出:5
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution: def findLength(self, nums1: List[int], nums2: List[int]) -> int: dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] result = 0
for i in range(1, len(nums1) + 1): for j in range(1, len(nums2) + 1): if nums1[i - 1] == nums2[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 if dp[i][j] > result: result = dp[i][j]
return result
|
1143.最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
- 例如,
"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
示例 1:
1 2 3
| 输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace" ,它的长度为 3 。
|
示例 2:
1 2 3
| 输入:text1 = "abc", text2 = "abc" 输出:3 解释:最长公共子序列是 "abc" ,它的长度为 3 。
|
示例 3:
1 2 3
| 输入:text1 = "abc", text2 = "def" 输出:0 解释:两个字符串没有公共子序列,返回 0 。
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: dp = [[0] * (len(text2) + 1) for _ in range(len(text1) + 1)] for i in range(1, len(text1) + 1): for j in range(1, len(text2) + 1): if text1[i - 1] == text2[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) return dp[len(text1)][len(text2)]
|
1035.不相交的线
在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。
现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足满足:
nums1[i] == nums2[j]
- 且绘制的直线不与任何其他连线(非水平线)相交。
请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。
以这种方法绘制线条,并返回可以绘制的最大连线数。
示例 1:

1 2 3 4
| 输入:nums1 = [1,4,2], nums2 = [1,2,4] 输出:2 解释:可以画出两条不交叉的线,如上图所示。 但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。
|
示例 2:
1 2
| 输入:nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2] 输出:3
|
示例 3:
1 2
| 输入:nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1] 输出:2
|