LeetCode #70 #746 #55 #45 2018-08-22

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]

你可能感兴趣的:(LeetCode #70 #746 #55 #45 2018-08-22)