力扣——2498、青蛙过河 II

227 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

力扣——2498、青蛙过河 II

2498. 青蛙过河 II

难度中等11收藏分享切换为英文接收动态反馈

给你一个下标从 0 开始的整数数组 stones ,数组中的元素 严格递增 ,表示一条河中石头的位置。

一只青蛙一开始在第一块石头上,它想到达最后一块石头,然后回到第一块石头。同时每块石头 至多 到达 一次。

一次跳跃的 长度 是青蛙跳跃前和跳跃后所在两块石头之间的距离。

  • 更正式的,如果青蛙从 stones[i] 跳到 stones[j] ,跳跃的长度为 |stones[i] - stones[j]|

一条路径的 代价 是这条路径里的 最大跳跃长度

请你返回这只青蛙的 最小代价

示例 1:

img

输入:stones = [0,2,5,6,7]
输出:5
解释:上图展示了一条最优路径。
这条路径的代价是 5 ,是这条路径中的最大跳跃长度。
无法得到一条代价小于 5 的路径,我们返回 5 。

示例 2:

img

输入:stones = [0,3,9]
输出:9
解释:
青蛙可以直接跳到最后一块石头,然后跳回第一块石头。
在这条路径中,每次跳跃长度都是 9 。所以路径代价是 max(9, 9) = 9 。
这是可行路径中的最小代价。

提示:

  • 2 <= stones.length <= 105
  • 0 <= stones[i] <= 109
  • stones[0] == 0
  • stones 中的元素严格递增。

问题解析

二分答案。

我们枚举可能的最小代价mid,然后判断这个最小代价是否可行。

check函数:我们每次都在最小代价范围内跳的尽量的远,如果当前所处的石头距离最近的石头距离大于mid的话,说明我们无法以mid为最小代价跳到结尾并跳回来。我们先用此方式从头跳到位,同时把这一趟走过的石头删掉,然后再回头走一遍,看能不能走回开头。

AC代码

class Solution {
public:
    bool check(int mid,vector<int>&stones)
    {
        int n=stones.size();
        vector<int>st(n);
        int idx=0;
        while(idx<n-2)
        {
            int pos=idx;
            while(pos+1<n&&stones[pos+1]-stones[idx]<=mid)
                pos++;
            if(idx==pos)return false;
            idx=pos;
            st[idx]=1;
        }
        idx=n-1;
        while(idx>0)
        {
            int pos=idx,ans=stones[idx];
            while(pos-1>=0&&ans-stones[pos-1]<=mid)
            {
                pos--;
                if(st[pos]==1)
                    continue;
                else 
                    idx=pos;
            }
                
            if(stones[idx]==ans)return false;
            st[idx]=1;
        }
        return true;
    }
    int maxJump(vector<int>& stones) {
        int l=0,r=stones.back()-stones[0];
        while(l<r)
        {
            int mid=(l+r)/2;
            if(check(mid,stones))
                r=mid;
            else 
                l=mid+1;
        }
        return l;
    }
};