You are standing at position 0 on an infinite number line. There is a goal at position target.

On each move, you can either go left or right. During the n-th move (starting from 1), you take n steps.

Return the minimum number of steps required to reach the destination.

Example 1:

Input: target = 3
Output: 2
Explanation:
On the first move we step from 0 to 1.
On the second step we step from 1 to 3.

Example 2:

Input: target = 2
Output: 3
Explanation:
On the first move we step from 0 to 1.
On the second move we step from 1 to -1.
On the third move we step from -1 to 2.

Note:

  • target will be a non-zero integer in the range [-10^9, 10^9].

这道题让我们从起点0开始,每次可以向数轴的左右两个方向中的任意一个走,第一步走距离1,第二步走距离2,以此类推,第n步走距离n,然后给了我们一个目标值 target,问我们最少用多少步可以到达这个值。博主分析了给的两个例子后,开始想的是用贪婪算法来做,就是如果加上距离大于目标值的话,就减去这个距离,到是当目标值是4的话,贪婪算法会fail。一般贪婪算法不行的话,很自然的博主就会想想能否用DP来做,但这道题感觉很难很难重现为子问题,因为每一步走的步数都不一样,这个步数又跟最小步数息息相关,所以很难写出状态转移方程啊,只得放弃。后来博主尝试用 BFS 来做,就是每次都把当前能到大的所有的点,都加上和减去当前距离,形成新的位置,加入数组中,当某个新的位置达到目标值时返回,但是这种解法会TLE,当目标值很大的话,相当的不高效。其实这道题的正确解法用到了些数学知识,还有一些小 trick,首先来说说小 trick,第一个 trick 是到达 target 和 -target 的步数相同,因为数轴是对称的,只要将到达 target 的每步的距离都取反,就能到达 -target。下面来说第二个 trick,这个是解题的关键,比如说目标值是4,那么如果我们一直累加步数,直到其正好大于等于target时,有:

0 + 1 = 1

1 + 2 = 3

3 + 3 = 6

第三步加上3,得到了6,超过了目标值4,超过了的距离为2,是偶数,那么实际上我们只要将加上距离为1的时候,不加1,而是加 -1,那么此时累加和就损失了2,那么正好能到目标值4,如下:

0 - 1 = -1

-1 + 2 = 1

1 + 3 = 4

那么,我们的第二个 trick 就是,当超过目标值的差值d为偶数时,只要将第 d/2 步的距离取反,就能得到目标值,此时的步数即为到达目标值的步数。那么,如果d为奇数时,且当前为第n步,那么我们看下一步 n+1 的奇偶,如果 n+1 为奇数,那么加上 n+1 再做差,得到的差值就为偶数了,问题解决,如果 n+1 为偶数,那么还得加上 n+2 这个奇数,才能让差值为偶数,这样就多加了两步。分析到这里,我们的解题思路也就明晰了吧:

我们先对 target 取绝对值,因为正负不影响最小步数。然后我们求出第n步,使得从1累加到n刚好大于等于 target,那么利用求和公式就有:

target = n * (n + 1) / 2

变成一元二次方程方程即为:

n^2 + n - 2*target = 0

用初中的一元二次方程的求和公式,就有:

n = (-1 + sqrt(1 + 8*target)) / 2

当然算出来可能不是整数,所以要取整,这里使用 ceil 来取整。如果此时 sum 和 target 正好相等,perfect!直接返回n,否则就是计算差值,如果差值时偶数,那么也直接返回n,如果是奇数,判断此时n的奇偶,如果n是奇数,则返回 n+2,若n是偶数,返回 n+1,参见代码如下:

解法一:

class Solution {
public:
int reachNumber(int target) {
target = abs(target);
long n = ceil((-1.0 + sqrt( + 8.0 * target)) / );
long sum = n * (n + ) / ;
if (sum == target) return n;
long res = sum - target;
if ((res & ) == ) return n;
return n + ((n & ) ? : );
}
};

我们也可以不用求和公式来快速定位n,而是通过累加来做,res 为我们的当前步数,也是最终需要返回的结果,sum 是加上每步距离的累加值,如果 sum 小于 target,或者 sum 减去 target 的差值为奇数,我们进行循环,步数 res 自增1,然后 sum 加上步数 res,最后跳出循环的条件就是差值为偶数,也符合我们上的分析,参见代码如下:

解法二:

class Solution {
public:
int reachNumber(int target) {
target = abs(target);
int res = , sum = ;
while (sum < target || (sum - target) % == ) {
++res;
sum += res;
}
return res;
}
};

下面这种解法是解法一的精简版,两行搞定碉堡了!

解法三:

class Solution {
public:
int reachNumber(int target) {
int n = ceil((sqrt( + 8.0 * abs(target)) - ) / ), d = n * (n + ) / - target;
return n + (d % ) * (n % + );
}
};

参考资料:

https://leetcode.com/problems/reach-a-number/

https://leetcode.com/problems/reach-a-number/discuss/112969/C++-O(1)-Solution-without-loop

https://leetcode.com/problems/reach-a-number/discuss/112992/Learn-from-other-with-my-explanations

https://leetcode.com/problems/reach-a-number/discuss/112982/2-liner-a-math-problem-with-explanation

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Reach a Number 达到一个数字的更多相关文章

  1. [LeetCode] Convert a Number to Hexadecimal 数字转为十六进制

    Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s compl ...

  2. LeetCode 202. Happy Number (快乐数字)

    Write an algorithm to determine if a number is "happy". A happy number is a number defined ...

  3. [LeetCode] 268. Missing Number ☆(丢失的数字)

    转载:http://www.cnblogs.com/grandyang/p/4756677.html Given an array containing n distinct numbers take ...

  4. [LeetCode] 268. Missing Number 缺失的数字

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  5. LeetCode 754. Reach a Number到达终点数字

    题目 在一根无限长的数轴上,你站在0的位置.终点在target的位置. 每次你可以选择向左或向右移动.第 n 次移动(从 1 开始),可以走 n 步. 返回到达终点需要的最小移动次数. 示例 1: 输 ...

  6. Python3解leetcode Reach a Number

    问题描述: You are standing at position 0 on an infinite number line. There is a goal at position target. ...

  7. leetcode 136. Single Number 、 137. Single Number II 、 260. Single Number III(剑指offer40 数组中只出现一次的数字)

    136. Single Number 除了一个数字,其他数字都出现了两遍. 用亦或解决,亦或的特点:1.相同的数结果为0,不同的数结果为1 2.与自己亦或为0,与0亦或为原来的数 class Solu ...

  8. [LeetCode] Missing Number 丢失的数字

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  9. [LeetCode] Single Number 单独的数字

    Given an array of integers, every element appears twice except for one. Find that single one. Note:Y ...

随机推荐

  1. 以太坊开发DApp入门教程——区块链投票系统(一)

    概述 对初学者,首先要了解以太坊开发相关的基本概念.   学习以太坊开发的一般前序知识要求,最好对以下技术已经有一些基本了解: 一种面向对象的开发语言,例如:Python,Ruby,Java... 前 ...

  2. Spark Job的提交与task本地化分析(源码阅读)

    Spark中任务的处理也要考虑数据的本地性(locality),Spark目前支持PROCESS_LOCAL(本地进程).NODE_LOCAL(本地节点).NODE_PREF.RACK_LOCAL(本 ...

  3. windows下apache报os 10048错误

    在apache的bin目录下运行httpd -k install,报错os10048 (错误信息是跟443端口有关),网上的答案说的是改掉httpd.conf里的默认端口或者关闭占用端口的进程,默认端 ...

  4. 网络1711c语言函数作业总结

    作业地址:https://edu.cnblogs.com/campus/jmu/JMUC--NE17111712/homework/1335 总结 1.评分细则 评分注意事项 代码规范问题依旧要重视, ...

  5. Dijkstra算法课后补分博客

    题目名称:Dijkstra算法 题目要求:课上给出相关附图,求解附图顶点A的单源最短路径. 附图: 做题过程 1.了解Dijkstra算法的相关知识,包括定义以及使用方法. 定义:Dijkstra算法 ...

  6. java从网络中下载图片到本地

    public class imageDownload { public static void main(String[] args) { String url = "http://loca ...

  7. raid5 / raid5e / raid5ee的性能对比及其数据恢复原理

    RAID 5 是一种存储性能.数据安全和存储成本兼顾的存储解决方案. RAID 5可以理解为是RAID 0和RAID 1的折中方案.RAID 5可以为系统提供数据安全保障,但保障程度要比Mirror低 ...

  8. nyoj 复杂度

    复杂度 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) for(k=j+1;k ...

  9. nyoj 非洲小孩

    非洲小孩 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 家住非洲的小孩,都很黑.为什么呢?第一,他们地处热带,太阳辐射严重.第二,他们不经常洗澡.(常年缺水,怎么洗 ...

  10. D的下L

    D的小L 时间限制:4000 ms  |  内存限制:65535 KB 难度:2   描述       一天TC的匡匡找ACM的小L玩三国杀,但是这会小L忙着哩,不想和匡匡玩但又怕匡匡生气,这时小L给 ...