数学专题1 - leetcode268. Missing Number/62. Unique Paths/462. Minimum Moves to Equal Array Elements II

268. Missing Number - easy

题目描述

给定一个包含n个不同数字的数组,数字来自0, 1, 2, …, n,找到缺失的数字。

例子
Example 1:

Input: [3,0,1]
Output: 2

Example 2:

Input: [9,6,4,2,3,5,7,0,1]
Output: 8

思想
要求时间复杂度-O(n),空间复杂度O(1)
利用数学:0…n的和为n(n+1)/2,然后减去sum(nums)
解法

class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        return n*(n+1)//2 - sum(nums)

62. Unique Paths

题目描述

在m*n方格的左上角有一个机器人,机器人每次只能向下或向右移动。问机器人到达右下角有多少中不同走法?

例子
Example 1:

Input: m = 3, n = 2
Output: 3

Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1.Right -> Right -> Down
2.Right -> Down -> Right
3.Down -> Right -> Right

Example 2:

Input: m = 7, n = 3
Output: 28

思想
(法1 - DP)
dp[i][j] = dp[i-1][j] + dp[i][j-1]
当然可以优化空间

(法2 - 数学解法)
从(1,1)到达(m,n),则机器人一共走了m+n-2步。在这些步数中,一共向下走m-1步,向右走n-1步,所以结果为组合数为 C m + n − 2 m − 1 = ( m + n − 2 ) ! ( m − 1 ) ! ( n − 1 ) ! C_{m + n - 2}^{m - 1} = {{\left( {m + n - 2} \right)!} \over {\left( {m - 1} \right)!\left( {n - 1} \right)!}} Cm+n2m1=(m1)!(n1)!(m+n2)!

解法1
DP,复杂度:时间-O(mn),空间-O(mn)

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        dp = [[0] * n for _ in range(m)]
        
        for i in range(m):
            for j in range(n):
                if i == 0 or j == 0:
                    dp[i][j] = 1
                else:
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[-1][-1]

(空间优化)时间-O(mn),空间-O(n)

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        dp = [0] * n
        
        for i in range(m):
            for j in range(n):
                if i == 0 or j == 0:
                    dp[j] = 1
                else:
                    dp[j] += dp[j-1]
        return dp[-1]

解法2
组合数。

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        p1 = p2 = 1
        for i in range(m, m+n-1):    # p2: 1..n
            p1 *= i
            p2 *= (i-m+1)
        return p1/p2 

462. Minimum Moves to Equal Array Elements II

题目描述

给定一个非空的整数数组,求解使得数组所有元素相等的最小移动次数。移动 - 所选元素加1或减1

例子

Input: [1,2,3]
Output: 2

Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]

思想
假设数组长度为n,最终的目标值为target = nums[i]。则有i个数比target小,有n-i个数大于等于target。
(法1 - 计算)
将nums排序,则前i个数的移动次数为target - num;后n-i个数的移动次数为num - target,所以总移动次数为
∑ i = 0 n − 1 ∣ n u m s [ i ] − t a r g e t ∣ =    i × t a r g e t − n u m s [ : i ] + n u m s [ i : ] − ( n − i ) × t a r g e t =    n u m s [ i : ] − n u m s [ : i ] + i × t a r g e t − ( n − i ) × t a r g e t =    s u m ( n u m s ) + ( 2 i − n ) × t a r g e t − 2 × n u m s [ : i ] \begin{aligned} \sum\limits_{i = 0}^{n - 1} {\left| {nums[i] - {\rm{target}}} \right|} = &\; i \times {\rm{target}} - nums[:i]{\rm{ + }}nums[i:] - (n - i) \times {\rm{target }} \\ = &\; nums[i:] - nums[:i]{\rm{ + i}} \times {\rm{target}} - (n - i) \times {\rm{target }} \\ = &\; {\rm{sum(}}nums{\rm{)}}+({\rm{2}}i - n) \times {\rm{target}} - {\rm{2}} \times nums[:i] \end{aligned} i=0n1nums[i]target===i×targetnums[:i]+nums[i:](ni)×targetnums[i:]nums[:i]+i×target(ni)×targetsum(nums)+(2in)×target2×nums[:i]

所以只需 min ⁡ ( ( 2 i − n ) × t a r g e t − 2 × n u m s [ : i ] ) , t a r g e t = n u m s [ i ] \min (({\rm{2}}i - n) \times {\rm{target}} - {\rm{2}} \times nums[:i]), \quad target{\rm{ = }}nums[i] min((2in)×target2×nums[:i]),target=nums[i]

(法2 - 优化) - 取中位数即可
排序后,target为数组中的某个数;则所需求解目标为
min ⁡ ( ∑ i = 0 n − 1 ∣ n u m s [ i ] − t a r g e t ∣ ) \min \left( {\sum\limits_{i = 0}^{n - 1} {\left| {nums[i] - {\rm{target}}} \right|} } \right) min(i=0n1nums[i]target)
当target取值为中位数时,上式取得最小值。

证明如下
若数组长度2m+1为奇数,则中位数左右两边各有m个数。设左边所有数与中位数的差值和为x, 右边所有数与中位数的差值和为y。
1)选择中位数:则所有需要移动的次数为x+y。
2)不选择中位数,例如选择median-1。则左边的数移动到median-1需要(x-n)次,而中位数右边的数移动到median-1需要(y+n)次,同时中位数还需移动一次。这样总的移动次数 = (x-n) + (y+n) + 1 = x+y+1
若数组长度为偶数,这种情况下中位数为两个,选择任意一个均可以。可以先让左中位数左边的数都移动到左中位数的位置右中位数…,然后两者拼接。

解法1
复杂度:时间-O(nlogn)排序;空间-O(1)

class Solution(object):
    def minMoves2(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums.sort()
        
        summ = sum(nums)
        prev = 0
        n = len(nums)
        cnt = float('inf')
        for i in range(n):
            cnt = min(cnt, summ + (2*i-n)*nums[i] - 2*prev)
            prev += nums[i]
        return cnt

解法2
target取中位数即可。

class Solution(object):
    def minMoves2(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums.sort()
        median = nums[len(nums)//2]
        cnt = 0
        for num in nums:
            cnt += abs(num - median)
        return cnt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值