【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)。(BFPRT应该是可以解决有重复值这个小问题的,But还不会............................> _ < )

通过代码如下:

方法一

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 select(median, 0, groups - 1, groups // 2)  # 求出生成好的median数组的中位数,作为partation函数的划分值

        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小

原文地址:https://www.cnblogs.com/ldy-miss/p/12035290.html

时间: 2024-10-16 07:48:45

【Leetcode Top-K问题 BFPRT】第三大的数(414)的相关文章

[LeetCode] Top K Frequent Elements 前K个高频元素

Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2,2,3] and k = 2, return [1,2]. Note: You may assume k is always valid, 1 ≤ k ≤ number of unique elements.    Your algorithm's time complexity must be

[LeetCode]Top K Frequent Elements

题目描述: Given a non-empty array of integers, return the k most frequent elements. For example, Given [1,1,1,2,2,3] and k = 2, return [1,2]. Note: You may assume k is always valid, 1 ≤ k ≤ number of unique elements. Your algorithm's time complexity must

LeetCode OJ 347. Top K Frequent Elements hashmap+排序求解

题目链接:https://leetcode.com/problems/top-k-frequent-elements/. 347. Top K Frequent Elements My Submissions QuestionEditorial Solution Total Accepted: 15510 Total Submissions: 36453 Difficulty: Medium Given a non-empty array of integers, return the k mo

Top k 问题

Top K的问题: 给出大量数据,找出其中前K个最大(小)的数,或者在海量数据中找到出现频率最好的前K个数. 一.给出大量数据(N个),找出其中前K个最大数(没有其他资源上的限制) 1.使用排序算法 直接使用排序算法,如快速排序,然后遍历找到最大的K个数.时间复杂度为O(NlogN): 2.部分排序 因为,只要求出前K个最大值,所以我们不必全部排好.思路是:随意选出K个数形成一个数组,然后按从大到小进行排序,再从剩下的数中,选取一个数和数组中的最小值进行比较,若小于最小值,则取下一个数继续比较:

Top K以及java priorityqueue

Top K问题比较常见啦,这里总结一下方法. 1.用最小堆来做. 思路是先利用数组中前k个数字建一个最小堆,然后将剩余元素与堆顶元素进行比较,如果某个元素比堆顶元素大,就替换掉堆顶元素,并且重新调整成最小堆. 到这里,堆中保存着的其实是前k个最大的数字.堆顶就是第K个最大的数字.这样前k个,第k个都可以求出来了.代码如下: 1 public void find(int[] nums, int k){ 2 PriorityQueue<Integer> priorityQueue = new Pr

Top K问题的两种解决思路

Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如: 从20亿个数字的文本中,找出最大的前100个. 解决Top K问题有两种思路, 最直观:小顶堆(大顶堆 -> 最小100个数): 较高效:Quick Select算法. LeetCode上有一个问题215. Kth Largest Element in an Array,类似于Top K问题. 1. 堆 小顶堆(min-heap)有个重要的性质--每个结点的值均不大于其左右孩子结点的值,则堆顶元素即为整个堆的最小值.J

排序算法Java版,以及各自的复杂度,以及由堆排序产生的top K问题

常用的排序算法包括: 冒泡排序:每次在无序队列里将相邻两个数依次进行比较,将小数调换到前面, 逐次比较,直至将最大的数移到最后.最将剩下的N-1个数继续比较,将次大数移至倒数第二.依此规律,直至比较结束.时间复杂度:O(n^2) 选择排序:每次在无序队列中"选择"出最大值,放到有序队列的最后,并从无序队列中去除该值(具体实现略有区别).时间复杂度:O(n^2) 直接插入排序:始终定义第一个元素为有序的,将元素逐个插入到有序排列之中,其特点是要不断的 移动数据,空出一个适当的位置,把待插

347. Top K Frequent Elements

Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2,2,3] and k = 2, return [1,2]. Note: 347. Top K Frequent ElementsYou may assume k is always valid, 1 ≤ k ≤ number of unique elements. Your algorithm's

Top K Frequent Words

Given a list of words and an integer k, return the top k frequent words in the list. Given [ "yes", "lint", "code", "yes", "code", "baby", "you", "baby", "chrome", &