利用快排和堆排序寻找无序数组中的第K大数

最近遇到的几个小问题,记录一下~~~
1、【快排和堆排序实现寻找第K大数】
快排和堆排序实现寻找第K大数github地址
2、【两个二维数组相乘】

3、【wmd讲解】

4、【三个激活函数的优缺点】

5、【LSTM解决的问题以及解决方法】

6、【fasttext原理】

7、【字典树的原理】

8、【过拟合 欠拟合了怎么办】

9、【正则项的作用】

1、求第K大数

leetcode # 215

【解法1 快排+分治算法】

利用快速排序算法找到pivotIndex(前后的分界点,左边的全都大于pivotIndex,右边的全都小于pivotIndex),判断当前pivot与K的大小关系

if pivotIndex == k: return nums[pivotIndex]

if pivotIndex > K : 只需要对数组前pivotIndex-1个进行递归找第K大数

if pivotIndex < K: 只需要对数组中pivotIndex+1后的进行递归

主要是利用一个Partition函数,得到分界点。这里提供两种写法的Partition函数。我觉得第一种比较好理解啦~~~

这里是从大到小进行排序,左边的全部大于pivotINDEX,右边的全部小于。

【Partition函数 第一种写法】

 def partition(self, nums, begin, end):
        left = begin +1
        right = end
        while left <= right:
            if nums[left] < nums[begin] and nums[right] > nums[begin]:
                nums[left],nums[right] = nums[right],nums[left]
            if nums[left] >= nums[begin]: left += 1
            if nums[right] <= nums[begin]: right -= 1
        nums[begin], nums[right] = nums[right],nums[begin]
        return right

【Partition函数 第二种写法】

 def Partition(self, nums, left, right):
        pivot = left
        index = pivot+1
        i = index
        while i <= right:
            if nums[i] > nums[pivot]:
                nums[i], nums[index] = nums[index], nums[i]
                index += 1
            i += 1
        nums[pivot], nums[index-1] = nums[index-1], nums[pivot]
        return index - 1

【找第K大数】

就是利用上述Partition函数找到分界点的index,然后判断跟K的大小。
也是有两种,一种传入left和right,一种不传入。


    def findKthLargest(self, nums, k):
        pivot = nums[0]
        left = 0
        right = len(nums)-1
        while True:
            pos = self.partition(nums, left, right)
            if pos == k-1:
                return nums[pos]
            if pos < k-1:
                left = pos+ 1
            else: right = pos- 1
# 这个函数有个bug,return的值为空,但是能够print出来,不知道什么原因。

def findKthLargest(self, nums, k, left = None, right = None):
        left = 0 if not isinstance(left, (int,float)) else left
        right  = len(nums)-1 if not isinstance(right, (int, float)) else right
#         print(left, right)
        index = self.Partition(nums, left, right)
        val = k-1
        if index == val :
            return nums[index]
        if index < val :
            self.findKthLargest(nums, k, index+1,right)
        else:
            self.findKthLargest(nums, k, left, index-1)

【解法二 利用堆排序】

堆排序时间复杂度的讲解

根据上述讲解,结论就是
哪个算法更加好?

Max: Time: O(n + klog(n)) | Space: O(n)
Min: Time: O(k) + O((n-k) * logk) | Space: O(K)

如果考虑k无限接近n
Max: O(n + nlog(n)) ~= O(nlogn)
Min: O(n + logk) ~= O(n)

如果考虑k = 0.5n
Max: O(n + nlogn)
Min: O(n + nlogn)

如果考虑n 无限大
Max: O(constant * n) 为什么是constant * n,参考
Min: O(log(k) * n)

都是利用shiftdown进行建堆

【最大堆寻找第k大数】

class FindKthLargestNum_maxHeap():
    def buildHeap(self,nums):
        if nums == []:
            return None
        size = len(nums)
        for i in range(size//2-1, -1,-1):
            self.shiftdown(nums, i, size)
        return nums

    def shiftdown(self, nums, i, size):
        left = 2*i +1
        right = 2*i +2
        maxIndex = i
        if left < size and nums[left] > nums[maxIndex]:
            maxIndex = left
        if right < size and nums[right] > nums[maxIndex]:
            maxIndex = right
        if maxIndex != i:
            nums[maxIndex], nums[i] = nums[i], nums[maxIndex]
            self.shiftdown(nums, maxIndex,size)
        return nums

    def findKthLargestNum(self,nums, k):
        self.buildHeap(nums)
        for i in range(len(nums)-1, len(nums)-k, -1):
            nums[i] , nums[0] = nums[0], nums[i]
            self.shiftdown(nums, 0, i)
        return nums[0]
if __name__ == '__main__':
    a = [21,42,59,83,20,25,16]
    k = 3
    res = FindKthLargestNum_maxHeap().findKthLargestNum(a, k)
    print('kth largest num is',res)

【用最小堆找第K大数】

class FindKthLargestNum_maxHeap():
    def buildHeap(self,nums):
        if nums == []:
            return None
        size = len(nums)
        for i in range(size//2-1, -1,-1):
            self.shiftdown(nums, i, size)
        return nums

    def shiftdown(self, nums, i, size):
        left = 2*i +1
        right = 2*i +2
        minIndex = i
        if left < size and nums[left] < nums[minIndex]:
            minIndex = left
        if right < size and nums[right] < nums[minIndex]:
            minIndex = right
        if minIndex != i:
            nums[minIndex], nums[i] = nums[i], nums[minIndex]
            self.shiftdown(nums, minIndex,size)
        return nums

    def findKthLargestNum(self,nums, k):
        self.buildHeap(nums)
        for i in range(len(nums)-1, k-1, -1):
            print(i,nums)
            nums[i] , nums[0] = nums[0], nums[i]
            self.shiftdown(nums, 0, i)
        return nums[0]
if __name__ == '__main__':
    a = [21,42,59,83,20,25,16]
    k = 4
    res = FindKthLargestNum_maxHeap().findKthLargestNum(a, k)
    print('kth largest num is',res)

你可能感兴趣的:(数据结构)