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步,所以結果為組合數為
解法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,所以總移動次數為
所以只需
(法2 - 優化) - 取中位數即可 排序後,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