1. 程式人生 > >leetcode268. Missing Number/62. Unique Paths/462. Minimum Moves to Equal Array Elements II

leetcode268. Missing Number/62. Unique Paths/462. Minimum Moves to Equal Array Elements II

題目描述

給定一個包含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)

題目描述

在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步,所以結果為組合數為Cm+n2m1=(m+n2)!(m1)!(n1)!C_{m + n - 2}^{m - 1} = {{\left( {m + n - 2} \right)!} \over {\left( {m - 1} \right)!\left( {n - 1} \right)!}}

解法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 

題目描述

給定一個非空的整數陣列,求解使得陣列所有元素相等的最小移動次數。移動 - 所選元素加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=0n1nums[i]target=  i×targetnums[:i]+nums[i:](ni)×target=  nums[i:]nums[:i]+i×target(ni)×target=  sum(nums)+(2in)×target2×nums[: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}

所以只需min((2in)×target2×nums[:i]),target=nums[i]\min (({\rm{2}}i - n) \times {\rm{target}} - {\rm{2}} \times nums[:i]), \quad target{\rm{ = }}nums[i]

(法2 - 優化) - 取中位數即可 排序後,target為陣列中的某個數;則所需求解目標為 min(i=0n1nums[i]target)\min \left( {\sum\limits_{i = 0}^{n - 1} {\left| {nums[i] - {\rm{target}}} \right|} } \right) 當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