【Leetcode】1340. Jump Game V 【动态规划/记忆性搜索】

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的节点进行对比

猜你喜欢

转载自www.cnblogs.com/xiyang2020/p/12918444.html