Frog Jump II

Frog Jump II

You are given a 0-indexed integer array stones sorted in strictly increasing order representing the positions of stones in a river.

A frog, initially on the first stone, wants to travel to the last stone and then return to the first stone. However, it can jump to any stone at most once.

The length of a jump is the absolute difference between the position of the stone the frog is currently on and the position of the stone to which the frog jumps.

More formally, if the frog is at stones[i] and is jumping to stones[j] , the length of the jump is |stones[i] - stones[j]|.
The cost of a path is the maximum length of a jump among all jumps in the path.

Return the minimum cost of a path for the frog.

Example 1:

Input: stones = [0,2,5,6,7]
Output: 5
Explanation: The above figure represents one of the optimal paths the frog can take.
The cost of this path is 5, which is the maximum length of a jump.
Since it is not possible to achieve a cost of less than 5, we return it.

Example 2:

Input: stones = [0,3,9]
Output: 9
Explanation: 
The frog can jump directly to the last stone and come back to the first stone. 
In this case, the length of each jump will be 9. The cost for the path will be max(9, 9) = 9.
It can be shown that this is the minimum achievable cost.

Constraints:

  • $2 \leq \text{stones.length} \leq {10}^{5}$
  • $0 \leq \text{stones}[i] \leq {10}^{9}$
  • $\text{stones}[0] ~\mathrm{==}~  0$
  • $\text{stones is sorted in a strictly increasing order}$.

 

解题思路

  思维题,证明也不太容易证,这里就直接贴出大佬给出的证明,这种题直接当结论来记就行了。解法就是每次隔着一个石头跳,去的时候隔着一个石头跳,如果最后无法隔着跳就直接跳到另外一块石头上,那么回来的时候自然也会隔着一个石头跳。

现在,假设我们已经得到了一个可行方案那么对方案中的瓶颈,即最远的一次跳跃进行分情况讨论:

1. 瓶颈跨过$0$点:

显然,该瓶颈已无法优化。且这两点分别为起点和终点,否则必然有比他还大的瓶颈。

2. 瓶颈跨过$1$点:

同样无法优化,即使改成单步跳,在返回时还是要面对这个瓶颈:

3. 瓶颈跨过$2$点:

显然,瓶颈可以优化:点$3$改为去的时候落脚,点$4$改为回的时候落脚,就可以在不改变原方案其他落脚点的情况下,将瓶颈转化为下面橙色的两段:

其他路径中,只有绿色的那条变长了,但如果该路径跨过$1$点,则无法被优化,若跨过多于$k$$(k>1)$个点,则可以继续优化。

4. 瓶颈跨过$k$点:

同理,可以在不改变其他落点的情况下将原来瓶颈变为跨越$k-1$个点:

唯一变长了的绿色路径不会让最优解变坏:

  • 如果绿色路径只跨过$1$个点,就让最瓶颈变坏,则原来的红色路径不可能是瓶颈。【我的理解:这是因为回来的时候必然存在一条比红色路径更长的路径,因此矛盾】
  • 如果绿色路径跨过多点,可以在保持红色路径为瓶颈的情况下转化成跨过$1$个点的情况。

可以得出结论:

  1. 瓶颈为跨越$0$个点的跳跃,只存在于只有首尾两个点的情况。
  2. 瓶颈为跨越$1$个点的跳跃,无法被优化。
  3. 瓶颈为跨越$k$$(k>1)$个点的跳跃,均可以被更小跨越数的方案所取代。

根据上面三个结论可以发现,间隔跳一定是一种最优策略。

作者:licold
链接:https://leetcode.cn/problems/frog-jump-ii/solution/tan-xin-ce-lue-zheng-ming-er-fen-fa-shi-dicog/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  AC代码如下:

 1 class Solution {
 2 public:
 3     int maxJump(vector<int>& stones) {
 4         int n = stones.size();
 5         int ret = 0;
 6         for (int i = 0; i < n; i += 2) {
 7             ret = max(ret, stones[min(n - 1, i + 2)] - stones[i]);
 8         }
 9         for (int i = 1; i < n; i += 2) {    // 往回跳,等价于从0跳到n-1,可以发现最后一定是从1跳到0,因此从1开始隔一个石头跳到n-1
10             ret = max(ret, stones[min(n - 1, i + 2)] - stones[i]);
11         }
12         return ret;
13     }
14 };

  这题还可以用二分,不过比赛的时候对二分的思想还不是很熟,没写出了。

  要用二分就要分析是否存在二段性。直接二分答案(值域),假设能够取到的最小代价为$\text{ans}$,因此如果$x < \text{ans}$就不可能存在一种跳跃方案,如果$x \geq \text{ans}$,因为当$x = \text{ans}$时存在一种跳越方案,因此如果条件放宽了(也就是$x > \text{ans}$)那么也一定存在一种跳越方案(代价不超过$x$,而已经存在一种代价为$\text{ans}$的方案),因此存在二段性。

  在写$\text{check}$的时候为了保证代价尽可能不超过(如果可以的话)给定的$\text{mid}$,那么从$0$跳到$n-1$时应该尽可能隔着多的石头跳(在保证跳越距离不超过$\text{mid}$的条件下),那么回来的时候跳越距离就会尽可能的小。

  AC代码如下:

 1 class Solution {
 2 public:
 3     int maxJump(vector<int>& stones) {
 4         int n = stones.size();
 5         int l = 0, r = stones.back() - stones[0];
 6         function<bool(int)> check = [&](int len) {
 7             vector<bool> vis(n);
 8             for (int i = 0; i < n - 1; i++) {
 9                 int j = i;
10                 while (j + 1 < n && stones[j + 1] - stones[i] <= len) {
11                     j++;
12                 }
13                 if (j == i) return false;   // 表示无法从i跳到下一个石头
14                 vis[j] = true;
15                 i = j - 1;
16             }
17             for (int i = n - 2, j = n - 1; i >= 0; i--) {
18                 if (!vis[i]) {
19                     if (stones[j] - stones[i] > len) return false;
20                     j = i;
21                 }
22             }
23             return true;
24         };
25         while (l < r) {
26             int mid = l + r >> 1;
27             if (check(mid)) r = mid;
28             else l = mid + 1;
29         }
30         return l;
31     }
32 };

 

参考资料

  【时光】图解贪心策略 + 二分法实现:https://leetcode.cn/problems/frog-jump-ii/solution/tan-xin-ce-lue-zheng-ming-er-fen-fa-shi-dicog/

posted @ 2023-01-11 10:15  onlyblues  阅读(35)  评论(0编辑  收藏  举报
Web Analytics