Part 2 – Sequence Dynamic Programming
这类题目是动态规划当中中等难度的,递推量相对固定,但递推式需要根据题目的要求做出相应的变化。同样当我们明确了4个主要元素,问题就会迎刃而解。
1)确定递推量。res[i]一般表示第i个位置/数字/字母的状态;
2)推导递推式。一般可以研究res[i]之前的res[j]对res[i]的影响;
3)计算初始条件。res[0]/res[n - 1];
4)考虑存储历史信息的空间维度(可选)。一般就是一维空间,不可优化。
70. Climbing Stairs
https://leetcode.com/problems/climbing-stairs/description/
res[i]表示前i个位置跳到第i个位置的方案总数,递推式res[i] = res[i - 1] + res[i - 2],典型的Fabonacci数列。初始化res[0] = 1, res[1] = 1,递推得到结果。
代码如下:
class Solution:
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
f0 = 1
f1 = 1
for i in range(1, n):
f2 = f0 + f1
f0, f1 = f1, f2
return f2
746. Min Cost Climbing Stairs
https://leetcode.com/problems/min-cost-climbing-stairs/description/
cost[i]表示通过当前位置需要的最小cost数值,递推式cost[i] = min(cost[i-1], cost[i-2]) + cost[i],注意边界条件,注意最后可选下标为-1或者-2两种情况即可。
代码如下:
class Solution:
def minCostClimbingStairs(self, cost):
"""
:type cost: List[int]
:rtype: int
"""
if len(cost) == 1:
return cost[0]
if len(cost) == 2:
return min(cost)
for i in range(2, len(cost)):
cost[i] += min(cost[i-1], cost[i-2])
return min(cost[-1], cost[-2])
55. Jump Game
https://leetcode.com/problems/jump-game/description/
其实这道题使用贪心算法比较好,所以第一种我们提供一个贪心算法的解法。虽然LeetCode加入了Test Case:[25000, 24999, 24998…]之后动态规划会超时,但动态规划的思想还是很值得借鉴。所以第二种是原版模板动态规划解法,第三种是针对该题优化版的动态规划解法。优化点1:既然某点可达,那么它前面的点肯定全部可达。优化点2:如果某点不可达了,直接返回false即可,不需要再往后计算了。
代码如下:
class Solution:
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
reach = 0
for i in range(len(nums)):
if i > reach:
return False
reach = max(reach, i + nums[i])
return True
动态规划代码是之前用java写的,仅供参考。
代码如下:
// DP-Original-TLE
public boolean canJump(int[] A) {
if(A == null || A.length == 0){
return true;
}
boolean[] reachable = new boolean[A.length];
reachable[0] = true;
for(int i = 1; i < A.length; i++){
for(int j = 0; j < i; j++){
if(reachable[j] && A[j] + j >= i){
reachable[i] = true;
break;
}
}
}
return reachable[A.length - 1];
}
// DP-Optimized-TLE
public boolean canJump(int[] A) {
if(A == null || A.length == 0){
return true;
}
for(int i = 1; i < A.length; i++){
boolean reachable = false;
for(int j = 0; j < i; j++){
if(A[j] + j >= i){
reachable = true;
break;
}
}
if(!reachable){
return false;
}
}
return true;
}
45. Jump Game II
https://leetcode.com/problems/jump-game-ii/description/
同样解法一使用贪心算法。
代码如下:
class Solution:
def jump(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
step = 0
reach = 0
lastReach = 0
for i in range(len(nums)):
if i > lastReach:
step += 1
lastReach = reach
if lastReach >= len(nums) - 1:
return step
reach = max(reach, nums[i] + i)
return -1
解法二使用模板动态规划,但会超时。
class Solution:
def jump(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
res = [0] * len(nums)
for i in range(1, len(nums)):
res[i] = i
for j in range(i):
if j + nums[j] >= i:
res[i] = min(res[i], res[j] + 1)
return res[-1]
网友评论