LeetCode 面试经典150题---003

#### 55. 跳跃游戏

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。
1 <= nums.length <= 104
0 <= nums[i] <= 105
本题题意比较明确,我们可以将题目转化为找到多条相交的线段,最终就一定能够到达终点,如图所示。
image
上方的线表示每个元素最远能到达的位置,红线是相交的线段。下方的线是实际的路径,可以看出对于相交的线段,我们始终可以达到相交部分的点,再从相交部分的点到达更远的点,因为有相交说明上一点到相交点和相交点到更远点都能到达。
那代码怎么写。我们定义j为此时的最远距离,每次都会维护j这个最远距离,同时每次循环每个元素i,试想对于当前最远距离j,j前面的每个位置i的i+nums[i]都小于j,那就说明最远只能到达j,跳不出j,因此更远的地方永远无法到达。如果j之前的位置i存在i+nums[i]大于j,说明可以从i跳到更远的大于j的位置,那么这样就组成了两条相交的线段啦。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        for(int i = 0, j = 0;i < nums.size();i ++ ){
            if(i > j) return false;
            j = max(j, i + nums[i]);
        }
        return true;
    }
};

#### 45. 跳跃游戏 II
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处。返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。
1 <= nums.length <= 104
0 <= nums[i] <= 1000
这题和上一题一样,不过这题要求跳跃的最小次数。我们考虑用动态规划,至于为什么用动态规划,因为它长得就像动态规划。我们定义f[i]为到达i的最小步数,那么如何维护f[i]呢,可以直接遍历从0-i-1的所有元素j,更新f[i]=min(f[i],f[j]+1),因为要到达i肯定是从i前面的某个位置跳跃而来。但是这样的话复杂度是O(n2),现在来考虑怎么优化。
分析可得,f[i]其实是个非递减数组,原因如下(1)对于f[i]和f[i+1],最好的情况是二者相等,即上一个点既可以跳到i也可以跳到i+1;(2)如果上一个点只能跳到i,那么f[i+1]就要比f[1]大1,要多跳一次。因此f[i]是一个非递减数组。回到刚刚的暴力做法,我们遍历i前面的所有j,其实我们只需要找到第一个能到达i的位置j,因为如果再往后的话,找到的f[j]都是大于等于第一个f[j]的,因此对答案没有影响,那为什么还要继续遍历呢,所以找到第一个就可以了。

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n);
        for(int i = 1,j = 0;i < n;i ++ ){
            while(j + nums[j] < i) j ++;
            f[i] = f[j] + 1;
        }
        return f[n - 1];
    }
};

总结,贪心和动态规划的知识点比较多,但是自己太菜了,所以基本都是看的题解,哈哈哈。

posted @   吃瓜吃撑了  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示