乐趣区

关于后端:754-到达终点数字-逐步剖析如何取得最小步数

题目形容

这是 LeetCode 上的 754. 达到起点数字 ,难度为 中等

Tag :「数学」

在一根有限长的数轴上,你站在 0 的地位。起点在 target 的地位。

你能够做一些数量的挪动 numMoves :

  • 每次你能够抉择向左或向右挪动。
  • i 次挪动(从  i == 1 开始,到 i == numMoves),在抉择的方向上走 i 步。

给定整数 target,返回 达到指标所需的 最小 挪动次数(即最小 numMoves )。

示例 1:

输出: target = 2

输入: 3

解释:
第一次挪动,从 0 到 1。第二次挪动,从 1 到 -1。第三次挪动,从 -1 到 2。

示例 2:

输出: target = 3

输入: 2

解释:
第一次挪动,从 0 到 1。第二次挪动,从 1 到 3。

提醒:

  • $-10^9 <= target <= 10^9$
  • $target != 0$

数学

提醒一:数轴上的任意点都以终点($0$ 点)对称,只须要思考对称点的任意一边

因为题目没有限度咱们「不能到达哪些点」以及「登程的起始方向」,因而以终点为核心的左右两边对称。

即:右边所能达到任意一个点,都能通过调整所达门路的方向来将起点调整到左边。

同时因为终点是一个非凡的地位 $0$ 点,因而相应的「正数点」和「正数点」对称,咱们仅需思考一边(例如负数域)即可。

提醒二:先往凑近 target 的方向挪动,达到或越过 target 的时候则进行

只思考 target 为正的状况,咱们假设起始先往凑近 target 的方向挪动(即所有步数均为正值),依据是「达到」还是「越过」target 地位分状况探讨:

  • 若能间接达到 target,此时耗费的必然是最小步数,可间接返回;
  • 若越过了 target,假如此时耗费的步数为 $k$,所走的间隔为 $dist = \frac{k \times (k + 1)}{2} > target$,咱们能够思考是否须要减少额定步数来达到 target

提醒三:越过 target 时,如何不引入额定步数

若不引入额定步数,意味着咱们须要将此前某些挪动的方向进行翻转,使得调整后的 $dist = target$。

咱们假如须要调整的步数总和为 tot,则有 $dist – 2 \times tot = target$,变形可得 $tot = \frac{dist – target}{2}$。

若想满足上述性质,须要确保能找到这样的 tot,即 tot 非法,

不难推导出当 disttarget 差值为「偶数」时(两者奇偶性雷同),咱们能够找到这样的 tot,从而实现不引入额定步数来达到 target 地位。

因为咱们的 $dist$ 是由数列 $[1,2,3,…,k]$ 累加而来,因而必然可能在该数列 $[1,2,3…k]$ 中通过「不反复抉择某些数」来凑成任意一个小于等于 $dist$ 的数。

提醒四:越过 target 时,如何尽量减少引入额定步数

disttarget 差值不为「偶数」时,咱们只能通过引入额定步数(持续往右走)来使得,两者差值为偶数。

能够证实,最多引入步数不超过 $4$ 步,可应用得两者奇偶性雷同,即不超过 $4$ 步能够笼罩到「奇数」和「偶数」两种状况。

依据 $k$ 与 $4$ 的余数关系分状况探讨:

  • 余数为 $0$,即 $k = 4X$,因为 $dist = \frac{k(k+1)}{2} = \frac{4X(4X+1)}{2} = 2X(4X+1)$,其中一数为偶数,$dist$ 为偶数;
  • 余数为 $1$,即 $k = 4X + 1$,因为 $dist = \frac{k(k+1)}{2} = \frac{(4X+1)(4X+2)}{2} = (4X+1)(2X+1)$,两个奇数相乘为奇数,$dist$ 为奇数;
  • 余数为 $2$,即 $k = 4X + 2$,$dist = \frac{k(k+1)}{2} = \frac{(4X+2)(4X+3)}{2} = (2X+1)(4X+3)$,两个奇数相乘为奇数,$dist$ 为奇数;
  • 余数为 $3$,即 $k = 4X + 3$,$dist = \frac{k(k+1)}{2} = \frac{(4X+3)(4X+4)}{2} = (4X+3)(2X+2)$,其中一数为偶数,$dist$ 为偶数。

因而在越过 target 后,最多引入不超过 $4$ 步可使得 disttarget 奇偶性雷同。

提醒五:如何不通过「遍历」或「二分」的形式找到一个适合的 k 值,再通过不超过 $4$ 步的调整找到答案

咱们冀望找到一个适合的 k 值,使得 $dist = \frac{k \times (k + 1)}{2} < target$,随后通过减少 k 值来找到答案。

利用求和公式 $dist = \frac{k \times (k + 1)}{2}$,咱们能够设定 $k = \left \lfloor \sqrt{2 \times target}) \right \rfloor$ 为起始值,随后逐渐增大 k 值,直到满足「disttarget 奇偶性雷同」。

Java 代码:

class Solution {public int reachNumber(int target) {if (target < 0) target = -target;
        int k = (int) Math.sqrt(2 * target), dist = k * (k + 1) / 2;
        while (dist < target || (dist - target) % 2 == 1) {
            k++;
            dist = k * (k + 1) / 2;
        }
        return k;
    }
}

TypeScript 代码:

function reachNumber(target: number): number {if (target < 0) target = -target
    let k = Math.floor(Math.sqrt(2 * target)), dist = k * (k + 1) / 2
    while (dist < target || (dist - target) % 2 == 1) {
        k++
        dist = k * (k + 1) / 2
    }
    return k
}

Python 代码:

class Solution:
    def reachNumber(self, target: int) -> int:
        if target < 0:
            target = -target
        k = int(math.sqrt(2 * target))
        dist = k * (k + 1) / 2
        while dist < target or (dist - target) % 2 == 1:
            k += 1
            dist = k * (k + 1) / 2
        return k
  • 工夫复杂度:$O(1)$
  • 空间复杂度:$O(1)$

最初

这是咱们「刷穿 LeetCode」系列文章的第 No.754 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,局部是有锁题,咱们将先把所有不带锁的题目刷完。

在这个系列文章外面,除了解说解题思路以外,还会尽可能给出最为简洁的代码。如果波及通解还会相应的代码模板。

为了不便各位同学可能电脑上进行调试和提交代码,我建设了相干的仓库:https://github.com/SharingSou…。

在仓库地址里,你能够看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其余优选题解。

更多更全更热门的「口试 / 面试」相干材料可拜访排版精美的 合集新基地 🎉🎉

本文由 mdnice 多平台公布

退出移动版