力扣题目链接:https://leetcode.cn/problems/reach-a-number/
在一根无限长的数轴上,你站在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 。
提示:
-109 <= target <= 109
target != 0
如果 t a r g e t < 0 target<0 target<0,那么我们就对 t a r g e t target target取个绝对值,因为走到 − 100 -100 −100和 100 100 100所需的步数是一样的
这样,我们就可以先头也不回地往右走,直到恰好走到 t a r g e t target target或超过 t a r g e t target target一两步为止
假设我们走了 n n n步,那么总距离就是 r e s u l t = n × ( n + 1 ) 2 result = \frac{n\times(n+1)}{2} result=2n×(n+1)
我们超过了 t a r g e t target target共 r e s u l t − t a r g e t result-target result−target,因此在这 n n n步中,我们希望有其中某步是往左的。
假设第 i i i步往左,那么我们 n n n步的总距离就是 r e s u l t − 2 × i result-2\times i result−2×i
也就是说往左一步
比一直往右
少走的距离一定是偶数。
因此,我们只需要在 r e s u l t ≥ t a r g e t result\geq target result≥target且 r e s u l t − t a r g e t result - target result−target不为偶数时,不断往右走
好了,现在我们超过 t a r g e t target target共 r e s u l t − t a r g e t result-target result−target,怎么办呢?我们将往右走的过程中,第 r e s u l t − t a r g e t 2 \frac{result-target}{2} 2result−target步改成向左走不就行了么?
问题解决。
有的同学可能不相信,那咱就举例说明一下。
假设目标距离是 2 2 2:
因此,我们只需要将第 4 2 = 2 \frac{4}{2}=2 24=2步修改为向左走,总行走距离就变成了 1 − 2 + 3 = 2 1-2+3=2 1−2+3=2。
这得益于几个条件:
总之,头也不回地往右走,直到超过 t a r g e t target target偶数的距离(或恰好位于 t a r g e t target target),修改历史某步为向左(不消耗步数),返回当前步数即可
\sqrt
)class Solution {
public:
int reachNumber(int target) {
unsigned to = abs(target);
unsigned n = 0;
while (true) {
unsigned result = n * (n + 1) / 2;
if (result >= to && (result - to) % 2 == 0)
return n;
n++;
}
}
};
方法一中我们从 1 1 1开始“枚举”了步数 n n n找到了 n × ( n + 1 ) 2 ≥ t a r g e t \frac{n\times(n+1)}{2}\geq target 2n×(n+1)≥target且 n × ( n + 1 ) 2 − t a r g e t \frac{n\times(n+1)}{2}- target 2n×(n+1)−target为偶数的最小 n n n
这导致时间复杂度为 log t a r g e t \log target logtarget
但是, n × ( n + 1 ) 2 \frac{n\times (n+1)}{2} 2n×(n+1)恰好略大于 t a r g e t target target,这就说明 n n n约等于 t a r g e t × 2 \sqrt{target\times2} target×2
因此我们从 t a r g e t × 2 − 2 \sqrt{target\times2} - 2 target×2−2开始枚举 n n n就好了,大约不出 5 5 5次就能找到答案。
aqrt()
的复杂度可以视作是
O
(
1
)
O(1)
O(1))class Solution {
public:
int reachNumber(int target) {
unsigned to = abs(target);
unsigned simN = max((int)sqrt(to * 2) - 2, 0);
while (true) {
unsigned result = simN * (simN + 1) / 2;
if (result >= to && (result - to) % 2 == 0)
return simN;
simN++;
}
}
};
执行结果确实快了点
同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/127684453