leetcode 2020年3月 每日一题打卡
剑指offer
面试经典题,评论里说微软考了类似的k问题。面试时一定要一边和考官沟通一边写代码,并且要分析时间复杂度。
题目:
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
思路: Top K 问题 有两种不同的解法,一种解法使用堆,另一种解法使用类似快速排序的分治法。(或者计数排序)
pi=k-1或k时,证明前面arr前面k个一定是最小的,结束;
pi
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
def partition(arr,low,high):
i=low-1
pivot=arr[high]
for j in range(low,high):
if arr[j]<=pivot:
i+=1
arr[i],arr[j]=arr[j],arr[i]
arr[i+1],arr[high]=arr[high],arr[i+1]
return (i+1)
# pi=k-1或k时,证明前面arr前面k个一定是最小的,结束
# pi
# pi>k,正好与pi
def quickSort(arr,low,high):
if low<high:
pi=partition(arr,low,high)
if pi == k-1 or pi == k:
return
elif pi < k-1:
quickSort(arr,pi+1,high)
else: # pi>k
quickSort(arr,low,pi-1)
quickSort(arr,0,len(arr)-1)
return arr[:k]
时间空间复杂度:
时间复杂度:分析方法和快速排序类似,T(N)=T(N/2)+O(N)=N + N/2 + N/4 + … + N/N = 2N,因此时间复杂度是O(N)。最坏情况下还是 O(n^2)。
空间复杂度:每次排序后问题化为原来的1/2,因此一共有logn层,每层O(1)空间,总共O(logn)。最坏情况n层共O(n)。
建立一个k大顶堆,如果再进来的元素比堆顶元素大,直接扔掉,如果比堆顶元素小,则替代堆顶元素。
堆排序代码:
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
# 建立一个k大顶堆,如果再进来的元素比堆顶元素大,直接扔掉,如果比堆顶元素小,则替代堆顶元素
def heapify(arr,i): #arr[0]为堆顶,i为放进来的需要调整的元素位置
largest=i
l=2*i+1
r=2*i+2
if l<k and arr[i]<arr[l]:
largest=l
if r<k and arr[largest]<arr[r]:
largest=r
if largest!=i:
arr[i],arr[largest]=arr[largest],arr[i]
heapify(arr,largest)
def heapSort(arr):
# build a k maxheap
for i in range(k-1,-1,-1): #先将前k个放入堆中
heapify(arr,i)
for i in range(k,len(arr)):
if arr[i]<arr[0]:
arr[i],arr[0]=arr[0],arr[i]
heapify(arr,0)
return arr[:k]
return heapSort(arr)
时间空间复杂度:
时间复杂度:入堆和出堆操作的时间复杂度均为 O(logk),每个元素都需要进行一次入堆操作,故算法的时间复杂度为 O(nlogk)。
空间复杂度:我的代码里没有利用优先队列,所以空间复杂度不是O(k)。每次建堆要O(3),共需要n次入堆,所以是3O(n)=O(n)。
本博客为原创作品,欢迎指导,转载请说明出处,附上本文链接,谢谢!