[leetcode日记]45.跳跃游戏Ⅱ

题目

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:

输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 说明:

假设你总是可以到达数组的最后一个位置。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/jump-game-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

动态规划,记录到某个位置的时候需要的最小步数。当能够到达一个新位置的时候比较(原来位置的步数+1)和(已经保存的最小步数),记录更新为更小的那个。
先尝试最暴力的手段。

代码

#define min(a,b) ((a)<(b)?(a):(b))
#define MAXSIZE 2147483647

int jump(int* nums, int numsSize){
    if (numsSize == 0 || numsSize == 1) return 0;

    int a[numsSize];
    a[0] = 0;
    for (int i = 1; i<numsSize ; i++){
        a[i] = MAXSIZE; 
    }
    for (int i = 0; i < numsSize ; i++){
        if (a[i] == MAXSIZE) return -1;
        for (int j = 0; j < nums[i] ; j++){
            if (i+j+1 >= numsSize) break;
            a[i+j+1] = min(a[i]+1,a[i+j+1]);
        } 
    }
    return a[numsSize-1]; 
}

运行结果:

在这里插入图片描述

分析2

毕竟是困难难度的题目,果然没有那么简单……
不得不说我的算法在时间复杂度上确实存在很大的优化空间。既然是超时,那么首先考虑算法的优化问题。因为我现在对每一个位置都需要进行多次更新,题目中又允许我们假定一定可以到最后一格,那么我们是否可以用贪心算法解决?每次我都尽可能地优先更新走的最远的那个格子,但是这样有个问题就是可能需要回溯(相当于要进行深度优先的搜索),那就需要记录跳跃的路径(当作回溯点),有没有避免回溯的方法呢……我想到了一种算法算是避免了回溯。

那就是贪心算法:每一步都尽可能的往远处走,我只需要记录最远那个格子以及它对应的步数就可以了,这样不但可以避免回溯,甚至可以在O(n)的条件下(而且最多遍历一次)完成题目要求。只需要从左往右遍历就可以。
如果采用从后往前遍历的话很可能会漏过某些更快到达的途径。

代码2

#define max(a,b) ((a)>(b)?(a):(b))

int jump(int* nums, int numsSize){
    int step = 0,end = 0 , farthest = 0,len = numsSize - 1;
    for (int i = 0; i < len; i++){
        farthest = max(nums[i] + i, farthest);
        if (i == end){
            end = farthest;
            step++;
        }
    }
    return step;
}

运行结果2

在这里插入图片描述
令人满意。这题其实只能算中等难度吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邵政道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值