代码随想录算法训练营第三十二天 | 122. 买卖股票的最佳时机II,55. 跳跃游戏,45. 跳跃游戏II

122. 买卖股票的最佳时机II

本题解法很巧妙,大家可以看题思考一下,在看题解。 

文章链接:代码随想录

重点:

1. 如果想到其实最终利润是可以分解的,那么本题就很容易了!

如何分解呢?

假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。

相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。

2. 局部最优:收集每天的正利润,全局最优:求得最大利润

思路:

1. 初始化result

int result = 0;

2. 拆分利润为每天利润,再只收集正利润

for (int i = 1; i < prices.length; i++) {
    result += Integer.max(prices[i] - prices[i - 1], 0);
}
public int maxProfit(int[] prices) {
    int result = 0;
    for (int i = 1; i < prices.length; i++) {
        result += Integer.max(prices[i] - prices[i - 1], 0);
    }
    return result;
}

55. 跳跃游戏

本题如果没接触过,很难想到,所以不要自己憋时间太久,读题思考一会,没思路立刻看题解 

文章链接:代码随想录

重点:

1. 跳跃覆盖范围究竟可不可以覆盖到终点!

2. 贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点

3. 这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。

思路:

1. 初始化覆盖范围,当nums长度为1时,直接返回true

int cover = 0;
if (nums.length == 1) {
    return true;
}

2. 循环遍历数组,不断更新cover为最大的cover,当能够覆盖数组到最后一个元素时,返回true

// 注意这里是小于等于cover
for (int i = 0; i <= cover; i++) {
    // 不断更新cover为最大的覆盖范围
    cover = Math.max(i + nums[i], cover);
    // 覆盖到终点了或者甚至超过终点了
    if (cover >= nums.length - 1) {
        return true;
    }
}
public boolean canJump(int[] nums) {
    int cover = 0;
    if (nums.length == 1) {
        return true;
    }
    // 注意这里是小于等于cover
    for (int i = 0; i <= cover; i++) {
        // 不断更新cover为最大的覆盖范围
        cover = Math.max(i + nums[i], cover);
        // 覆盖到终点了或者甚至超过终点了
        if (cover >= nums.length - 1) {
            return true;
        }
    }
    return false;
}

45. 跳跃游戏II

本题同样不容易想出来。贪心就是这样,有的时候 会感觉简单到离谱,有时候,难的不行,主要是不容易想到。
文章链接: 代码随想录

重点:

1. 局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。整体最优:一步尽可能多走,从而达到最少步数。

2. 两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点。

思路:

1. 初始化当前覆盖范围,下一步的最大覆盖范围,result

// 当前覆盖范围的最远距离下标
int curCover = 0;
// 下一步覆盖范围的最远距离下标
int nextCover = 0;
int result = 0;

2. 循环遍历当前的覆盖范围,不断更新下一步覆盖范围为最大范围。当前覆盖范围走完之后,说明已经走了一步,需要进入下一步,更新当前覆盖范围为下一步的最大范围。如果当前覆盖范围最远到达终点,直接break。注意,一开始curCover为0,刚刚进入这个for的时候就会进入if里了。

for (int i = 0; i < nums.length; i++) {
    // 更新下一步覆盖范围为最大的覆盖范围
    nextCover = Math.max(i + nums[i], nextCover);
    // 遇到当前覆盖范围的最远距离下标
    if (i == curCover) {
        // 已经走了一步
        result++;
        // 更新当前覆盖范围(相当于进入下一步)
        curCover = nextCover;
        // 当前覆盖范围最远到达终点,直接break
        if (nextCover >= nums.length - 1) {
            break;
        }
    }
}
public int jump(int[] nums) {
    if (nums.length == 1) {
        return 0;
    }
    // 当前覆盖范围的最远距离下标
    int curCover = 0;
    // 下一步覆盖范围的最远距离下标
    int nextCover = 0;
    int result = 0;
    for (int i = 0; i < nums.length; i++) {
        // 更新下一步覆盖范围为最大的覆盖范围
        nextCover = Math.max(i + nums[i], nextCover);
        // 遇到当前覆盖范围的最远距离下标
        if (i == curCover) {
            // 已经走了一步
            result++;
            // 更新当前覆盖范围(相当于进入下一步)
            curCover = nextCover;
            // 当前覆盖范围最远到达终点,直接break
            if (nextCover >= nums.length - 1) {
                break;
            }
        }
    }
    return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值