【Leetcode】1340. Jump Game V 【動態規劃/記憶性搜尋】

Yx_xixi發表於2020-05-19

Given an array of integers arr and an integer d. In one step you can jump from index i to index:

i + x where: i + x < arr.length and 0 < x <= d.
i - x where: i - x >= 0 and 0 < x <= d.
In addition, you can only jump from index i to index j if arr[i] > arr[j] and arr[i] > arr[k] for all indices k between i and j (More formally min(i, j) < k < max(i, j)).

You can choose any index of the array and start jumping. Return the maximum number of indices you can visit.

Notice that you can not jump outside of the array at any time.

題目來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/jump-game-v
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

-----------------------------------------------------------------------------------------------------------------

【難點分析】

某位置可訪問的最多節點數與周圍i-x ~ i+x的節點有關,容易想到用動態規劃的方法來做。然而一個節點能到達的節點數不僅與左半邊節點相關,也與右半邊節點相關,所以不能簡單的從0開始遍歷整個陣列。

 

【解決方案】:

方案一:

對可以訪問的節點數從1開始進行遍歷,即dp[i][j] 表示第i個節點是否可以訪問j個節點,直到左右dp[i][j]都為false時迴圈結束。對每一個dp[i][j],尋找他的左邊及右邊滿足條件的節點中可以使他為true的節點,一旦發現後便退出迴圈。

class Solution {
public:
    int maxJumps(vector<int>& arr, int d) {
        int n = arr.size();
        vector<vector<bool>> dp(n, vector<bool>(n+1, false));
        for(int i = 0; i < n; ++i)
            dp[i][0] = true;
        for(int jp = 1; jp <= n; jp++) {
            bool flag = false;
            for(int i = 0; i < n; ++i) {
                if(!dp[i][jp-1]) continue;
                for(int j = i-1; j >= 0 && i-j <= d && arr[j] < arr[i]; j--) {
                    if(dp[j][jp-1]) {
                        dp[i][jp] = true;
                        //cout << i << ", " << jp << endl;
                        flag = true;
                        break;
                    }
                }
                if(dp[i][jp]) continue;
                for(int j = i+1; j < n && j-i <= d && arr[j] < arr[i]; j++) {
                    if(dp[j][jp-1]) {
                        dp[i][jp] = true;
                        //cout << i << ", " << jp << endl;
                        flag = true;
                        break;
                    }
                }
            }
            if(!flag) return jp;
        }
        return n+1;
    }
};

時間複雜度:O(d*n^2) 

 

方案二.

對於需要根據未知狀態來確定當前狀態值的動態規劃問題,可以用記憶化搜尋方法來解決,即如果dp[i] = func(dp[j]), 若dp[j]還未求出,則先去求dp[j]。這種方法要注意的是是否存在迴圈的狀況,即類似於dp[i] = func(dp[j]), dp[j] = func(dp[k]), dp[k] = func(dp[i])。

因為本題中如果dp[i]需要由dp[j]來求得,則arr[j]必小於arr[i],dp[j]不可能由dp[i]直接或間接決定。

 

class Solution {
private:
    vector<int> jmp;
public:
    void dfs(vector<int>& arr, int id, int d) {
        if(jmp[id] != 0) return;
        jmp[id] = 1;
        for(int t = 1; t <= d && id+t < arr.size() && arr[id+t] < arr[id]; t++) {
            dfs(arr, id+t, d);
            jmp[id] = max(jmp[id], jmp[id+t]+1);
        }
        for(int t = 1; t <= d && id-t >= 0 && arr[id-t] < arr[id]; t++) {     
            
            dfs(arr, id-t, d);
            jmp[id] = max(jmp[id], jmp[id-t]+1);
        }
        
    }
    int maxJumps(vector<int>& arr, int d) {
        int n = arr.size();
        jmp.resize(n, 0);
        for(int i = 0; i < n; ++i) {
            dfs(arr, i, d);
        }
        return *max_element(jmp.begin(), jmp.end());
    }
};

 

時間複雜度: O(n*d) //每一個節點只需計算一次,需要與i-d ~ i+d的節點進行對比

相關文章