Reach a Number - LeetCode

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

  1. 如果D是偶数,那么只要把D/2前面的符号变成负号就可以了,即
    1 + 2 + ... - D/2 + D/2+1 + ... + k-1 + k = target
    这时候答案就是k

  2. 如果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的题,我还是把它记下来了,因为第一我没做对,第二我很喜欢这道题,它用了一些数学推导。这类题不多,加上我多年没碰数学,看到这道题的时候根本没往那方面想,以后碰到类似的题目就要多留个心眼。

你可能感兴趣的:(算法分析与设计,leetcode,python,算法)