leetcode 面试题40. 最小的k个数 面试 topK解法 快排变形/堆排序

leetcode 面试题40. 最小的k个数 面试 topK解法 快排变形/堆排序

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<k-1时,说明只找到了前pi个小的,并且第k个数在右侧数组,只需快排右侧即可;
pi>k,正好与pi<k-1的情况相反。
快排代码:

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<k-1时,说明只找到了前pi个小的,并且第k个数在右侧数组,只需快排右侧即可
        # pi>k,正好与pi<k-1的情况相反
        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)。

本博客为原创作品,欢迎指导,转载请说明出处,附上本文链接,谢谢!

发布了25 篇原创文章 · 获赞 1 · 访问量 287

猜你喜欢

转载自blog.csdn.net/weixin_43973433/article/details/104993953
今日推荐