数组中的第K个最大元素
法1:
用堆API做
def kthmaxnum(nums, k):
heap = []
for num in nums:
heapq.heappush(heap, num)
if len(heap) > k:
heapq.heappop(heap)
return heap[0]
- 时间复杂度:O(nlogk)
- 空间复杂度:O(k)
法2:
自己实现堆做
def kthMaxNum(nums, k):
#把num放进最小堆heap里
def heappush(heap,num):
heap.append(num)
i = len(heap) - 1
while i > 1 and heap[i] < heap[i // 2]:
heap[i], heap[i // 2] = heap[i // 2], heap[i]
i = i // 2
#删除heap里最小的元素
def heappop(heap):
n = len(heap) - 1
heap[1], heap[n] = heap[n], heap[1]
endnum = heap.pop()
#下沉第一个元素
i = 1
n -= 1
while i * 2 <= n:
less = i * 2
if i * 2 + 1 <= n and heap[i * 2 + 1] < heap[i * 2]:
less = i * 2 + 1
if heap[less] > heap[i]:
break
heap[i], heap[less] = heap[less], heap[i]
i = less
return endnum
res = [None]
for num in nums:
heappush(res, num)
if len(res) - 1 > k:
heappop(res)
return heappop(res)
法3:
快排法
def findKthNum(nums, k):
def partition(left,right):
if left == right:
return left
rand = random.randint(left, right)
nums[left], nums[rand] = nums[rand], nums[left]
pivot = nums[left]
i = left + 1
j = right
while True:
while i < right and nums[i] <= pivot:
i += 1
while j > left and nums[j] >= pivot:
j -= 1
if i >= j:
break
nums[i], nums[j] = nums[j], nums[i]
nums[left], nums[j] = nums[j], nums[left]
return j
left = 0
right = len(nums) - 1
n = len(nums)
while left <= right:
pos = partition(left, right)
if pos == n - k:
return nums[pos]
elif pos > n - k:
right = pos - 1
else:
left = pos + 1
return None
- 时间复杂度:O(n)
- 空间复杂度:O(1)
自己实现最小堆
class myHeap:
def __init__(self):
self.heap = [0]
self.N = 0
def parent(self,root):
return root // 2
def left(self,root):
return root * 2
def right(self,root):
return root * 2 + 1
"""
def minnum(self):
return self.heap[1]
"""
#上浮第k个元素
def swim(self,k):
while k > 1 and self.heap[self.parent(k)] > k:
self.heap[k], self.heap[self.parent(k)] = self.heap[self.parent(k)], self.heap[k]
k = self.parent(k)
#下沉第k个元素
def sink(self,k):
while self.left(k) <= self.N:
less = self.left(k)
if self.right(k) <= self.N and self.heap[self.right(k)] < self.heap[self.left(k)]:
less = self.right(k)
if k < self.heap[less]:
break
self.heap[less], self.heap[k] = self.heap[k], self.heap[less]
k = less
#插入一个元素
def insert(self,value):
self.N += 1
self.heap.append(value)
self.swim(self.N)
#删除最小元素
def delMin(self):
minValue = self.heap[1]
self.heap[1], self.heap[N] = self.heap[N], self.heap[1]
self.heap.pop()
self.N -= 1
self.sink(1)
return minValue
堆排序
def sortArray(nums):
def maxHepify(arr, i, end):
j = 2 * i
while j <= end:
if j + 1 <= end and arr[j+1] > arr[j]:
j += 1
if arr[i] < arr[j]:
arr[i], arr[j] = arr[j], arr[i]
i = j
j = 2 * i
else:
break
n = len(nums)
nums = [0] + nums
for i in range(n//2, 0, -1): #非叶子节点才需要下沉
maxHepify(nums, i, n)
for j in range(n, 0, -1):
nums[1], nums[j] = nums[j], nums[1]
maxHeapify(nums, 1, j-1)
return nums[1:]
- 时间复杂度:O(nlogn)
- 空间复杂度:O(1)
快速排序
def sortArray(self, nums: List[int]) -> List[int]:
def partition(left,right):
if left == right:
return left
rand = random.randint(left,right)
nums[rand], nums[left] = nums[left], nums[rand]
pivot = nums[left]
i = left + 1
j = right
while True:
while i < right and nums[i] <= pivot:
i += 1
while j > left and nums[j] >= pivot:
j -= 1
if i >= j :
break
nums[i], nums[j] = nums[j], nums[i]
nums[left], nums[j] = nums[j], nums[left]
return j
n = len(nums)
if n <= 1:
return nums
def sort_helper(left,right):
if left >= right:
return
p = partition(left, right)
sort_helper(left,p-1)
sort_helper(p+1,right)
sort_helper(0, n - 1)
return nums
- 时间复杂度:O(nlogn)
- 空间复杂度:O(logn)
归并排序
def sortArray(nums):
def merge_sort(arr,l,r):
if l == r:
return
mid = l + (r - l) // 2
merge_sort(arr, l, mid)
merge_sort(arr, mid + 1, r)
tmp = []
i = l #前半段起点
j = mid + 1 #后半段起点
while i <= mid or j <= r:
if i > mid or (j <= r and arr[j] < arr[i]):
tmp.append(nums[j])
j += 1
else:
tmp.append(nums[i])
i += 1
nums[l:r+1] = tmp
n = len(nums)
if n <= 1:
return nums
merge_sort(nums,0,n-1)
return nums
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n)
数据流的中位数
class MedianInData:
def __init__(self):
#左边最大堆,右边最小堆
self.maxHeap = []
self.minHeap = []
def addNum(self,value):
if not self.maxHeap or value <= -self.maxHeap[0]:
heapq.heappush(self.maxHeap, -value)
if len(self.maxHeap) > len(self.maxHeap) + 1:
heapq.heappush(self.minHeap, - heapq.heappop(self.maxHeap))
else:
heapq.heappush(self.minHeap, value)
if len(self.minHeap) > len(self.maxHeap):
heapq.heappush(self.maxHeap, - heapq.heappop(self.minHeap))
def findMedian(self):
if len(self.maxHeap) == len(self.minHeap):
return (- self.maxHeap[0] + self.minHeap[0]) / 2
else:
return - self.maxHeap[0]
- 时间复杂度:
- addNum: O(logn)
- findMedian:O(1)
- 空间复杂度:O(n)
寻找两个正序数组的中位数
def findMedian(nums1, nums2):
def findkthnum(k):
idx1 = 0
idx2 = 0
while True:
if idx2 == n:
return nums2[idx2 + k - 1]
if idx1 == m:
return nums1[idx1 + k - 1]
if k == 1:
return min(nums1[idx1],nums2[idx2])
newidx1 = min(idx1 + k // 2 - 1, m - 1)
newidx2 = min(idx2 + k // 2 - 1, n - 1)
if nums1[newidx1] <= nums2[newidx2]:
k -= newidx1 - idx1 + 1
idx1 = newidx1 + 1
else:
k -= newidx2 - idx2 + 1
idx2 = newidx2 + 1
m = len(nums1)
n = len(nums2)
k = (m + n) // 2
if (m + n) % 2 == 0:
return (findkthnum(k) + findkthnum(k+1)) / 2
else:
return findkthnum(k+1)
- 时间复杂度:O(log(m+n))
- 空间复杂度:O(1)
数组中的逆序对
def reversePairs(nums):
n = len(nums)
if n <= 1:
return 0
def merge_sort(nums,left,right):
if left >= right:
return
mid = left + (right - left) // 2
merge_sort(nums, left, mid)
merge_sort(nums, mid + 1, right)
tmp = []
i = left
j = mid + 1
while i <= mid or j <= right:
if i > mid :
tmp.append(nums[j])
j += 1
elif j > right or (nums[i] <= nums[j]):
tmp.append(nums[i])
i += 1
else:
tmp.append(nums[j])
self.res += mid + 1 - i
j += 1
nums[left:right+1] = tmp
self.res = 0
merge_sort(nums, 0, n - 1)
return self.res
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n)