到达终点数字【LC754】
You are standing at position
0
on an infinite number line. There is a destination at positiontarget
.You can make some number of moves
numMoves
so that:
- On each move, you can either go left or right.
- During the
ith
move (starting fromi == 1
toi == numMoves
), you takei
steps in the chosen direction.Given the integer
target
, return the minimum number of moves required (i.e., the minimumnumMoves
) to reach the destination.
在一根无限长的数轴上,你站在
0
的位置。终点在target
的位置。你可以做一些数量的移动
numMoves
:
- 每次你可以选择向左或向右移动。
- 第
i
次移动(从i == 1
开始,到i == numMoves
),在选择的方向上走i
步。给定整数
target
,返回 到达目标所需的 最小 移动次数(即最小numMoves
) 。
还好dp、递归写不出来,就直接看题解了,这不是我能想到的方法
-
思路
-
数轴上的任意点都以起点(0 点)对称,只需要考虑对称点的任意一边
左边所能到达任意一个点,都能通过调整所达路径的方向来将终点调整到右边。
-
先往靠近
target
的方向移动,到达或越过target
的时候则停止- 若能直接到达
target
,此时消耗的必然是最小步数,可直接返回; - 若越过了
target
,那么需要考虑是否需要增加额外步数到达target
- 若能直接到达
-
我们假设需要调整的步数总和为
tot
,则有$ dist−2×tot=target ,变形可得 ,变形可得 ,变形可得tot = \frac{dist - target}{2}$- 当
tot
为整数时,即$ dist−target$为偶数时,不需要引入额外步数,只需要将某些数反向即可 - 当
tot
不为整数时,即$ dist−target$为奇数时,只能引入额外步数,继续往右走,使两者差值为偶数
- 当
-
-
实现
class Solution { public int reachNumber(int target) { while (target < 0){ target = -target; } int dis = 0; int i = 1; while (dis < target || (dis > target && (dis - target) % 2 == 1 ) ){ dis += i; i++; } return i - 1; } }
-
复杂度
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
-
代码优化:利用等差数列的性质,找到第一个 S k > = t a r g e t S_k>=target Sk>=target
- 等差数列前n项和计算公式
S n = ( n + 1 ) ∗ ( a 0 + a n ) 2 S_n = \frac{(n+1)*(a_0+a_n)}{2} Sn=2(n+1)∗(a0+an)
a n = a 0 + n ∗ d a_n=a_0+n*d an=a0+n∗d
- 当 a 0 = 0 、 a 1 = 1 a_0=0、a_1=1 a0=0、a1=1、当前步数为k、d=1时,
S k = k ∗ ( k + 1 ) 2 S_k = \frac{k*(k+1)}{2} Sk=2k∗(k+1)
-
首先找到第一个 S k > = t a r g e t S_k>=target Sk>=target, k = s q r t ( 2 ∗ t a r g e t ) k=sqrt(2*target) k=sqrt(2∗target),此时移动的距离为 S k S_k Sk
-
代码
只需判断是否需要进行额外移动,额外移动最多4次
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; } }
-
复杂度
- 时间复杂度: O ( 1 ) O(1) O(1)
- 空间复杂度: O ( 1 ) O(1) O(1)