到达终点数字(Leetcode 754)

1

题目分析

   本题题意非常清晰,就是第i步,可以向左或者向右移动i个单位,问最后到达指定目标最少需要移动的次数。应该如何去求解呢?

数学

其实我一开始想的思路是搜索,但是题目的数据量太大了,如果是1e9的数据量,根据1 + 2 + … + step = 1e9,可以求出step约为1e4以上的量级。那么需要广搜10000步,因此需要2的10000次方的运算量。这是完全不现实的。

有的小伙伴就会提出质疑,是否可以用一个visited哈希表,记录已经遍历过的点呢?这也是不现实的,因为每一个点都会被遍历到,时间复杂度至少是1e9的,此时就不可能通过本题。而且最重要的一点是,当前遍历到x时无法抵达终点,不代表后面再次遍历到x无法抵达终点。这是这个方法无法使用的关键点。如0这个点,一开始就是0,假设无法抵达100,当第100步时,再次到达0,那么是可以抵达100的,如果使用visited哈希表,则认为0这个位置已经遍历过,不去考虑从0直接到100的情况,这是不对的。

所以本题无法使用暴力搜索,只能再想其他的方法。

因为本题是对称的,所以目标为负数的结果和目标为正数的结果相等。为了计算方便,可以先将目标变为正数。

我们可以想到,在一般情况下都会向终点方向移动。是不是可以先尽量向右侧移动。如果超过了目标,则可以将前面的某些步数向左移动呢?

首先找到超过目标的最小步数,根据等差数列求和可知

$$ step = \frac{-1 + \sqrt{1 + 8 \times target}}{2} $$

并且求得经过step步后到达的位置是n = (1 + step) x step

记此时所在位置n和target的差距为diff

下面有三种情况:

  1. 如果diff为偶数,那么直接将第diff / 2步的右移变为左移即可。这是很好理解的,将某一步x右移变为左移,距离就会减少2x。
  2. 如果diff为奇数,那么看n是奇数还是偶数,如果n是奇数,那么下一步n + 1一定是偶数,因此多走一步,diff仍然为奇数,所以还需要多走一步。
  3. 如果diff为奇数,n是偶数,那么下一步n + 1一定是奇数,此时diff是偶数,会变成情况1,因此多走一步即可。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Solution {
    public int reachNumber(int target) {
    target = Math.abs(target);
    int step = (int) Math.ceil((-1 + Math.sqrt(8L * target + 1)) / 2);
    int diff = (1 + step) * step / 2 - target;
    if ((diff & 1) == 0) {
    return step;
    }
    // 下面可以节省为1步,return step + 1 + (step & 1);
    if ((step & 1) == 0) {
    return step + 1;
    } else {
    return step + 2;
    }
    }
    }

刷题总结

  本题难度不大,但是很难想到,有些贪心的思想,小伙伴们遇到无法搜索的题目,一定要模拟一下,想一想是否可以使用贪心算法求解。

-------------本文结束感谢您的阅读-------------
0%