[LeetCode] Reach a Number 达到一个数字
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 达到一个数字的更多相关文章
- [LeetCode] Convert a Number to Hexadecimal 数字转为十六进制
Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s compl ...
- LeetCode 202. Happy Number (快乐数字)
Write an algorithm to determine if a number is "happy". A happy number is a number defined ...
- [LeetCode] 268. Missing Number ☆(丢失的数字)
转载:http://www.cnblogs.com/grandyang/p/4756677.html Given an array containing n distinct numbers take ...
- [LeetCode] 268. Missing Number 缺失的数字
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...
- LeetCode 754. Reach a Number到达终点数字
题目 在一根无限长的数轴上,你站在0的位置.终点在target的位置. 每次你可以选择向左或向右移动.第 n 次移动(从 1 开始),可以走 n 步. 返回到达终点需要的最小移动次数. 示例 1: 输 ...
- Python3解leetcode Reach a Number
问题描述: You are standing at position 0 on an infinite number line. There is a goal at position target. ...
- leetcode 136. Single Number 、 137. Single Number II 、 260. Single Number III(剑指offer40 数组中只出现一次的数字)
136. Single Number 除了一个数字,其他数字都出现了两遍. 用亦或解决,亦或的特点:1.相同的数结果为0,不同的数结果为1 2.与自己亦或为0,与0亦或为原来的数 class Solu ...
- [LeetCode] Missing Number 丢失的数字
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...
- [LeetCode] Single Number 单独的数字
Given an array of integers, every element appears twice except for one. Find that single one. Note:Y ...
随机推荐
- Java多线程:乐观锁、悲观锁、自旋锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...
- Jedis操作Redis
Jedis操作Redis的常用封装方法 @Resource(name="jedispool") private JedisPool pool=null; /** * 设置缓存对象过 ...
- 蓝桥杯java历年真题及答案整理1~20.md
蓝桥杯java历年真题及答案整理(闭关一个月,呕心沥血整理出来的) 1 算法是这样的,如果给定N个不同字符,将这N个字符全排列,最终的结果将会是N!种.如:给定 A.B.C三个不同的字符,则结果为:A ...
- Linux安装Python2.7.9
1.下载python wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz 2.解压.编译安装 tar -zxvf Python- ...
- ThreadLocal 原理和使用场景分析
ThreadLocal 不知道大家有没有用过,但至少听说过,今天主要记录一下 ThreadLocal 的原理和使用场景. 使用场景 直接定位到 ThreadLocal 的源码,可以看到源码注释中有很清 ...
- 结合jenkins在Linux服务器搭建测试环境
何时使用: 测试过程中我们需要持续构建一个软件项目,为避免重复的手动下载.解压操作,我们需要搭建一个能够自动构建的测试环境,当代码有更新时,测试人员只需点一下[构建]即可拉取最新的代码进行测试(也可设 ...
- 2018上C语言程序设计(高级)作业- 第1次作业
未来两周学习内容 复习指针的定义和引用 指针的应用场景: 指针作为函数参数(角色互换) 指针作为函数的参数返回多个值 指针.数组和地址间的关系 使用指针进行数组操作 数组名(指针)作为函数参数(冒泡排 ...
- Alpha冲刺No.8
一.站立式会议 解决真实手机中出现的各种问题 细化界面设计 数据库上传与获取日拍 二.项目实际进展 能够上传和获取日拍信息 界面设计微调 三.燃尽图 四.团队合照 五.总结 白天金工实习,晚上才有时间 ...
- C语言第二周作业
一.PTA实验作业 题目一:7-1 计算分段函数 1.实验代码 double x,y; scanf("%lf", &x); if(x >= 0){ y=pow(x,0 ...
- 201621123050 《Java程序设计》第9周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 ①foreach循环 for (String e : map.keyS ...