Leetcode每日一题 —— 1340. 跳跃游戏 V

力扣 LeetCode 1340. 跳跃游戏 V - 力扣(LeetCode) 1340. 跳跃游戏 V - 给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到: * i + x ,其中 i + x < arr.length 且 0 < x <= d 。 * i - x ,其中...
Leetcode每日一题 —— 1340. 跳跃游戏 V
Leetcode每日一题 —— 1340. 跳跃游戏 V
力扣 LeetCode

1340. 跳跃游戏 V - 力扣(LeetCode)

1340. 跳跃游戏 V - 给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到: * i + x ,其中 i + x < arr.length 且 0 < x <= d 。 * i - x ,其中 i - x >= 0 且 0 < x <= d 。 除此以外,你从下标 i 跳到下标 j 需要满足:arr[i] > arr[j] 且 arr[i] > arr[k] ,其中下标 k 是所有 i 到 j 之间的数字(更正式的,min(i, j) < k < max(i,...

还有第五关?!( °ヮ° )


思路

最开始看到这题脑子里会想能不能用栈做,一看输入规模,好像 O(n^2) 时间复杂度也可以接受。看了一眼提示后顿悟了,这题可以用动态规划。

动态规划 dp[i] 表示从 i 下标开始能跳跃的次数。

问题来了,我从哪个地方开始、按什么顺序递推呢?

  • 开始的地方应当不依赖于任何其他 dp 状态,符合这个要求的显然是最低的一个柱子,这样的地方 p 无法跳到其他任何地方,自然有 dp[p]=0 (只能访问自身,一次都跳不了)

  • 递推的时候我们只关注一个地方 i 能跳到哪些更矮的地方,然后可以尝试从这些地方中跳跃次数最多的柱子上转移过来。因此递推顺序也是沿着柱子高度来的。

  • 我们可以按照柱子高度对下标进行排序,顺着排序后的下标递推。

递推的过程中可以不断用 \max(\cdot) 更新最终结果。


思路

class Solution {
public:
    int maxJumps(vector<int>& arr, int d) {
        // 每个位置 i 可以跳到 [i-d, i+d] 区间内除 i 外的位置
        // 只能跳到更低的地方,且中间其余柱子都是更低的
        // 看了提示才知道是动态规划,但是从哪里开始递推呢?
        // 当然是最矮的那个柱子,从矮的到高的,最矮的柱子哪都别想跳
        int n=arr.size();
        vector<int> idxs;
        for(int i=0;i<n;i++){
            idxs.emplace_back(i);
        }
        // 对下标按照柱子高度进行排序
        sort(idxs.begin(),idxs.end(),[&](const int& a,const int& b){
            return arr[a]<arr[b];
        });
        // dp[i] 表示从 i 开始跳,能跳跃的下标个数
        int dp[n];
        memset(dp,0,sizeof(dp));
        // dp[idxs[0]]=0;
        int res=0;
        for(int i:idxs){
            // 从低到高处理
            // 往左、右走试试,只往更低的地方走,找到比 arr[i] 更低的柱子中能跳得最多的
            for(int k=1;k<=d;k++){
                if(i-k<0){
                    break;
                }
                if(arr[i-k]>=arr[i]){
                    break;
                }
                // 能走到这个柱子这里,看看能不能更新跳跃次数
                dp[i]=max(dp[i],dp[i-k]+1);
            }
            for(int k=1;k<=d;k++){
                if(i+k>=n){
                    break;
                }
                if(arr[i+k]>=arr[i]){
                    break;
                }
                // 能走到这个柱子这里,看看能不能更新跳跃次数
                dp[i]=max(dp[i],dp[i+k]+1);
            }
            res=max(res,dp[i]);
        }
        // 最终要的是能访问的下标数而不是跳数,所以 +1
        return res+1;
    }
};

2 个帖子 - 2 位参与者

阅读完整话题

来源: LinuxDo 最新话题查看原文