Reach a Number - LeetCode
题目:
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.
暴力解法bfs,亲测超时。
i = k时,会往q里增加2^k个数
class Solution(object):
def reachNumber(self, target):
"""
:type target: int
:rtype: int
"""
q = [-1, 1, '#']
i = 2
first = q[0]
while first != target:
if first == '#':
i = i + 1
q.append('#')
else:
q.append(first-i)
q.append(first+i)
q[:] = q[1:]
first = q[0]
return i-1
答案解法:
首先需要一些数学推导
这道题里正负是对称的,可以取target的绝对值,以下默认target > 0
找到k
使得
1 + 2 + ... + k-2 + k-1 < target
…①
1 + 2 + ... + k-2 + k-1 + k >= target
…②
令S = 1 + 2 + ... + k-1 + k
,则由①得S - k < target
=> S - target < k
令D = S - target
,则D < k, D/2 < k
-
如果
D
是偶数,那么只要把D/2
前面的符号变成负号就可以了,即
1 + 2 + ... - D/2 + D/2+1 + ... + k-1 + k = target
这时候答案就是k
-
如果
D
是奇数,那么{1,2,...,k-1,k}
这k
个数无论如何也凑不成target
因为改变任何一个数字前面的符号,S
的变化量总是偶数
例如把+3
变成-3
那么S
就减小了6
所以{1,2,...,k-1,k}
不能通过加减法凑成target考虑
{1,2,...,k-1,k,k+1}
,这时候
1 + 2 + ... + k-1 + k + k+1 - target = D + k+1 < 2k + 1
由于都是整数所以D + k+1 <= 2k
=>(D + k+1)/2 <= k
- 如果
D + k+1
为偶数,那么(D + k+1)/2 ∈ {1,2,...,k-1,k,k+1}
,只要把(D + k+1)/2
符号变成负就行了,最终答案就是k+1
- 如果
D + k+1
为奇数,那么D + k+1 + k+2
一定是偶数,(D + k+1 + k+2)/2 <= (3k+2)/2 < k + k+1
,所以一定可以从{1,2,...,k-1,k,k+1,k+2}
中找到几个数,使它们的和等于(D + k+1 + k+2)/2
,然后把这几个数的符号变成负号就行,这样最终答案就是k+2
- 如果
class Solution(object):
def reachNumber(self, target):
"""
:type target: int
:rtype: int
"""
target = abs(target)
s = 0
k = 0
while s < target:
k += 1
s += k
if s == target:
return k
elif s > target:
if (s-target)%2 == 0:
return k
elif (s+k+1-target)%2 == 0:
return k+1
else:
return k+2
这是LeetCode上一道难度为easy的题,我还是把它记下来了,因为第一我没做对,第二我很喜欢这道题,它用了一些数学推导。这类题不多,加上我多年没碰数学,看到这道题的时候根本没往那方面想,以后碰到类似的题目就要多留个心眼。