【LetMeFly】754.到达终点数字
力扣题目链接:leetcode.cn/problems/re…
在一根无限长的数轴上,你站在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 <= 109target != 0
方法一:枚举
如果,那么我们就对取个绝对值,因为走到和所需的步数是一样的
这样,我们就可以先头也不回地往右走,直到恰好走到或超过一两步为止
假设我们走了步,那么总距离就是
我们超过了共,因此在这步中,我们希望有其中某步是往左的。
假设第步往左,那么我们步的总距离就是
也就是说往左一步比一直往右少走的距离一定是偶数。
因此,我们只需要在且不为偶数时,不断往右走
好了,现在我们超过共,怎么办呢?我们将往右走的过程中,第步改成向左走不就行了么?
问题解决。
有的同学可能不相信,那咱就举例说明一下。
假设目标距离是:
- ,但是奇数
- 且是偶数
因此,我们只需要将第步修改为向左走,总行走距离就变成了。
这得益于几个条件:
- 将target取绝对值后,模板在原点或原点的右边,我们要尽可能地多往右走
- 如果一直往右走不能恰好到达,那么就一定要往左走“数次”
- “往左一次”只能比“全部往右”少走偶数的距离,这就导致了“把其中某一步”改为往左不一定能正好走到
- 假设这次超过奇数的距离,那么再往前走一步,一定会超过偶数的距离(这是因为我们是奇偶交替走的,总距离也是奇偶交替的),因此超过后最多再往前走一步,就能“将之前某一步改为向左以恰好达到target”(一定不大于)
总之,头也不回地往右走,直到超过偶数的距离(或恰好位于),修改历史某步为向左(不消耗步数),返回当前步数即可
- 时间复杂度(注意这里是“根号下target的绝对值”,目前力扣新版UI中无法正常显示
\sqrt) - 空间复杂度
AC代码
C++
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++;
}
}
};
方法二:基于方法一的小优化
方法一中我们从开始“枚举”了步数找到了且为偶数的最小
这导致时间复杂度为
但是,恰好略大于,这就说明约等于
因此我们从开始枚举就好了,大约不出次就能找到答案。
- 时间复杂度(CPU有专门的计算平方根的指令,
aqrt()的复杂度可以视作是) - 空间复杂度
AC代码
C++
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:letmefly.blog.csdn.net/article/det…