• 【Leetcode Top-K问题 BFPRT】第三大的数(414)


    题目

    给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)

    示例 1:

    输入: [3, 2, 1]
    输出: 1
    解释: 第三大的数是 1.
    

    示例 2:

    输入: [1, 2]
    输出: 2
    解释: 第三大的数不存在, 所以返回最大的数 2 .
    

    示例 3:

    输入: [2, 2, 3, 1]
    输出: 1
    解释: 注意,要求返回第三大的数,是指第三大且唯一出现的数。存在两个值为2的数,它们都排第二。
    

    解答

    思路:
    1,题目要求时间复杂度必须是O(n),那么排序肯定是不行了,由于只是求第三大,那么可以先求出第一大,再求出第二大,再求第三大,总的时间复杂度O(N)。
    2,BFPRT,专门解决TOP-K问题,但是因为序列中可能有重复值,所以在进行BFPRT之前,先去重,总的时间复杂度O(N)。

    (2020.1.7更)
    3,堆,大小为k的小顶堆,k=3。Time: N·log(k) = O(N), Space: O(1)
    4,二叉排序树,首先构建一颗二叉排序树,中序遍历得出从小到大的序列,取第K大。构建二叉排序树平均log(N),最差O(N),查找第K大O(N)
    5,AVL树,优化的二叉排序树,优化了构建二叉树的时间复杂度,最差log(N),中序遍历查找第K大O(N)

    通过代码如下:
    方法一

    class Solution:
        def thirdMax(self, nums: List[int]) -> int:
            l = list(set(nums))
            max_list = []
            sum = min(3, len(l))
    
            while sum:
                max = -float('inf')  # 负无穷
                for x in l:
                    if x > max and x not in max_list:
                        max = x
                if max not in max_list:
                    # l.remove(max)  remove时间复杂度为O(n)
                    del l[l.index(max)]
                    max_list.append(max)
                sum -= 1
            return max_list[-1] if len(max_list)>=3 else max_list[0]
    

    BFPRT

    class Solution:
        def thirdMax(self, nums) -> int:
            k = 3  # 代表求第三大
            nums = list(set(nums))
            if len(nums) < 3:
                return max(nums)
    
            def getmedian(lis):
                """返回序列lis中位数,在BFPRT中就是求每5个数小组的中位数"""
                begin = 0
                end = len(lis) - 1
    
                sum = begin + end
                mid = sum // 2 + sum % 2  # 这个地方加上sum%2是为了确保偶数个数时我们求的是中间两个数的后一个
                return sorted(lis)[mid]
    
            def BFPRT(nums, left, right):
                """分成每5个数一个小组,并求出每个小组内的中位数"""
                num = right - left + 1
                offset = 0 if num % 5 == 0 else 1  # 最后如果剩余的数不足5个,我们也将其分成一个小组,和前面同等对待
                groups = num // 5 + offset
                median = []  # 中位数数组
                for i in range(groups):
                    begin = left + i * 5
                    end = begin + 4
                    Median = getmedian(nums[begin:min(end, right) + 1])
                    median.append(Median)
                return getmedian(median)
    
            def partition(nums, left, right, base):
                """在 nums[left, right] 将基准base归位"""
                temp = nums[base]
                nums[base], nums[right] = nums[right], nums[base]  # 基准和末尾元素互换
    
                max_index = left
                for i in range(left, right):  # 把所有小于基准的移到左边
                    if nums[i] <= temp:  # 要等于啊!这里好坑的说.. 否则通不过[3, 3, 3, 3, 4, 3, 3, 3, 3]  k = 1
                        nums[max_index], nums[i] = nums[i], nums[max_index]
                        max_index += 1
                nums[right], nums[max_index] = nums[max_index], nums[right]  # 基准归位
                return max_index
    
            def select(nums, left, right, k_smallest):
                """在 nums[left, right] 找第k小的元素"""
                if left == right:  # 递归终止条件
                    return nums[left]
                # pivot_index = random.randint(left, right)
                base = BFPRT(nums, left, right)
                base_index = partition(nums, left, right, nums.index(base))  # 选base为基准,并归位。
                if base_index == k_smallest:  # 判断目前已归位的基准,是不是第k_smallest位
                    return nums[k_smallest]
                elif k_smallest < base_index:  # 递归左半部分
                    return select(nums, left, base_index - 1, k_smallest)
                else:  # 递归右半部分
                    return select(nums, base_index + 1, right, k_smallest)
    
            return select(nums, 0, len(nums) - 1, len(nums)-k)  # 第k大,是第n-k小
    
  • 相关阅读:
    起泡排序引申出的问题
    关于NPC和NP-Hard问题
    我的书单(更新中)
    OpenCV2学习笔记03:Qt中配置OpenCV环境
    Ubuntu 14.04为浏览器添加Flash插件
    CSS3基础
    HTML5进阶
    拖拽上传及读取文件实现
    生产者消费者模型
    进程
  • 原文地址:https://www.cnblogs.com/ldy-miss/p/12035290.html
Copyright © 2020-2023  润新知