• 以Jump Game为例,逐层击破动态规划


    本文以LeetCode上Jump Game为案例,分别用递归法、递归+动态规划、动态规划完成解答。
    (本文由DianeSoHungry原创,转载请说明出处!https://www.cnblogs.com/DianeSoHungry/p/11406212.html)
    语言:C++

    题目

    Given an array of non-negative integers, you are initially positioned at the first index of the array.
    Each element in the array represents your maximum jump length at that position.
    Determine if you are able to reach the last index.

    Example 1:

    Input: [2,3,1,1,4]
    Output: true
    Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
    

    Example 2:

    Input: [3,2,1,0,4]
    Output: false
    Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
    

    递归法

    思路是这样的:

    若你被放在下标为i的位置,判断你能到达终点的依据是“从当前位置往后到i+nums[i]位置,是否至少存在一个位置,从这个位置你能到达终点。

    //////recursive backtracking////////
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    bool canJump(int* nums, int n){
        if (n==1) {
            return true;
        }
        if (nums[0]==0) {
            return false;
        }
        bool res = false;
        for (int i = 1; i <= nums[0]; i++) {
            res = res || canJump(&nums[i], n-i);
        }
        return res;
    }
    
    int main(){
        int n;
        cin >> n;
        int nums[n];
        for (int i = 0; i < n; i++) {
            int num;
            scanf("%d", &num);
            nums[i] = num;
        }
        cout << canJump(nums, n);
        return 0;
    }
    

    递归 + 动态规划 (Top-down)

    单纯递归造成的问题是:重复。例如:nums=[5, 3, 4, 2]。位置2的返回既要被位置0调用,还要被位置1调用。加上memo记忆表使得当

    ////////recursion +  memoization table////////
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    bool canJump (int* nums, int* memo, int n) {
        if (memo[0] != -1) {
            return memo[0];
        }
        if (n == 1) {
            memo[0] = 1;
            return true;
        }
        if (nums[0]==0) {
            memo[0] = 0;
            return false;
        }
        bool res = false;
        for (int i = 1; i <= nums[0]; i++) {
            res = res || canJump(&nums[i], &memo[i], n-i);
        }
        memo[0] = res;
        return res;
    }
    
    int main(){
        int n;
        cin >> n;
        int nums[n];
        int memo[n];
        for (int i = 0; i < n; i++) {
            int num;
            scanf("%d", &num);
            nums[i] = num;
            memo[i] = -1;
        }
        cout << canJump(nums, memo, n);
        return 0;
    }
    

    动态规划(Bottom-up)

    该方法超时,下文利用原数组作为记忆表解决了超时问题。

    ////////Bottom-up Dynamic Programming////////
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    bool canJump(vector<int> &nums) {
        vector<bool> memo;
        for (int i = 0; i < nums.size(); i ++) {
            memo.push_back(false);
        }
        memo.back() = true;
        for (int i = nums.size() - 2; i > -1; i--) {
            for (int j = 1; j <= nums[i] && i+j < nums.size(); j++) {
                memo[i] = memo[i] || memo[i+j];
                if (memo[i] == true) {
                    break;
                }
            }
        }
        return memo[0];
        
    }
    
    int main(){
        int n;
        cin >> n;
        vector<int> nums;
        for (int i = 0; i < n; i++) {
            int num;
            scanf("%d", &num);
            nums.push_back(num);
        }
        cout << canJump(nums);
        return 0;
    }
    

    动态规划(Bottom-up & Inplace)

    ////////Bottom-up Dynamic Programming////////
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    bool canJump(vector<int> &nums){
        nums.back() = 1;
        for (int i = nums.size() - 2; i > -1; i--) {
            int tmp = 0;
            for (int j = 1; j <= nums[i] && i+j < nums.size(); j++) {
                tmp = tmp || nums[i+j];
                if (tmp) {
                    break;
                }
            }
            nums[i] = tmp;
            for (auto k:nums) {
                cout << k;
            }
            cout << endl;
        }
        return nums[0];
    }
    
    int main(){
        int n;
        cin >> n;
        vector<int> nums;
        for (int i = 0; i < n; i++) {
            int num;
            scanf("%d", &num);
            nums.push_back(num);
        }
        cout << canJump(nums);
        return 0;
    }
    
  • 相关阅读:
    Photoshop 2021 for Mac
    viscose live serves 扩展工具更改默认自动打开的浏览器
    UML面向对象分析、建模与设计
    Shell 脚本
    早做打算,不要随遇而安。
    编程人员成长模型
    Spring AOP详解
    Mybatis逆向工程的配置
    Int和String互转的方法
    SQL学习
  • 原文地址:https://www.cnblogs.com/DianeSoHungry/p/11406212.html
Copyright © 2020-2023  润新知