【力扣hot100】刷题笔记Day22

文章介绍了如何使用最小堆和快速排序算法解决LeetCode中的问题,如找到数组中第K个最大元素、前K个高频元素以及数据流的中位数。同时提及了Counter在统计元素频率的应用。
摘要由CSDN通过智能技术生成

前言

  • 局势紧迫起来了呀,同学们都开始找实习了,赶紧刷完hot100开找了

215. 数组中的第K个最大元素 - 力扣(LeetCode)

  • 计数排序:O(max(n,S))

    • class Solution:
          def findKthLargest(self, nums: List[int], k: int) -> int:
              # 使用计数排序
              # 统计数的范围 
              # -- 根据计数排序,还需统计数的范围,设定max-min+1的0值数组长度,且统计数时下标刚好-min来衡量
              # 本题已明确表明nums[i]范围为-10000-10000 因此可设定数组长度为20001
              count = [0] * 20001
              # 统计数组中每个值出现的次数
              for num in nums:
                  count[num + 10000] += 1
              # 因为要找数组中第k个最大的元素,因此从后往前遍历 寻找第k个最大的
              cnt = 0
              for i in range(len(count)-1, -1,-1):
                  cnt += count[i]
                  if cnt >= k:
                      return i - 10000
  • 最小堆:O(nlogk)

    • class Solution:
          def findKthLargest(self, nums: List[int], k: int) -> int:
              minheap = []  # 优先队列(最小堆),push和pop为O(logk)
              for num in nums:
                  heapq.heappush(minheap, num)  # 放入k个数,此时堆顶为最小值
                  if len(minheap) > k:          # 超过k个数就pop掉最小值
                      heapq.heappop(minheap)    # 剩下的就是前k大数
              return minheap[0]   # 堆顶就是第k大数
  •  快速排序:O(n)

    • # 快排模板
      def quick_sort(arr):
          if len(arr) <= 1:   # 递归结束
              return arr
          else:
              pivot = arr[0]  # 选择基准值
              less = [x for x in arr[1:] if x <= pivot]     # 小的放左边
              greater = [x for x in arr[1:] if x > pivot]   # 大的放右边
              return quick_sort(less) + [pivot] + quick_sort(greater)  # 重新组合
      
      
      class Solution:
          def findKthLargest(self, nums: List[int], k: int) -> int:
              def quick_sort(nums, k):
                  pivot = random.choice(nums)  # 随机选择基准数防止退化成O(n2)
                  big, equal, small = [], [], []  # 大于、等于、小于 pivot 的元素
                  for num in nums:
                      if num > pivot:
                          big.append(num)
                      elif num < pivot:
                          small.append(num)
                      else:
                          equal.append(num)
                  # 第k大元素在big里
                  if k <= len(big):   
                      return quick_sort(big, k)  # 递归进big里找
                  # 第k大元素在small里
                  elif k > len(nums) - len(small):  
                      return quick_sort(small, k - len(nums) + len(small))  # 递归进small里找
                  # 第k大元素在equal里,直接返回pivot
                  return pivot
              
              return quick_sort(nums, k) 

 347. 前 K 个高频元素 - 力扣(LeetCode)

  • 参考郁郁雨学姐的题解
  • 计数器:O(nlogn)

    • # 补充Counter用法,用于统计可哈希对象(比如列表、元组等)中每个元素的出现次数
      import collections
      nums = [1, 2, 3, 1, 2, 1]
      count = collections.Counter(nums)
      # 访问元素的计数
      print(count[1])  # 输出元素 1 出现的次数
      # 返回出现频率最高的元素及其出现次数
      most_common_elements = count.most_common(2)  # 频率最高的前两个元素及其次数
      print(most_common_elements)
      # 更新 Counter 对象
      count.update([1, 2, 3])  # 更新计数器以包括新元素
      # 删除元素或重置元素计数
      del count[1]  # 删除元素 1 的计数
      count.clear()  # 清空计数器
      
      class Solution:
          def topKFrequent(self, nums: List[int], k: int) -> List[int]:
              count = collections.Counter(nums)
              return [item[0] for item in count.most_common(k)]
  •  最小堆:O(nlogk)

    • class Solution:
          def topKFrequent(self, nums: List[int], k: int) -> List[int]:
              mp = {}  # 统计频率
              for num in nums:
                  mp[num] = mp.get(num, 0) + 1
              minheap = []
              for num, freq in mp.items():
                  heapq.heappush(minheap, (freq, num))  # 按照频率排序
                  if len(minheap) > k:          # 大于k就弹出最小值
                      heapq.heappop(minheap)  # 最后剩下频率前k
              return [item[1] for item in minheap]  # 返回频率前k的num
  • 快速排序:O(n)

    • 快速排序算法还是不太熟,找了个讲Python排序的视频学学
    • class Solution:
          def topKFrequent(self, nums: List[int], k: int) -> List[int]:
              mp = {}  # 统计频率
              for num in nums:
                  mp[num] = mp.get(num, 0) + 1
              # mp = collections.Counter(nums)
              num_cnt = list(mp.items())
              topKs = self.findTopK(num_cnt, k, 0, len(num_cnt)-1)
              return [item[0] for item in topKs]
          
          def findTopK(self, num, k, l, r):
              if l >= r: return num[:k]      # 递归到0/1个元素,说明已完成前k排序
              pivot = random.randint(l ,r)   # 随机选择基准值下标
              num[pivot], num[l] = num[l], num[pivot]  # 把基准数换到最左边
              pivot = l  # 更新基准值下标
              swap_i = pivot + 1  # 用于交换较小值
              for i in range(l + 1, r + 1):
                  if num[i][1] > num[pivot][1]:  # 把大于基准数的放左边(和快排相反)
                      num[i], num[swap_i] = num[swap_i], num[i]
                      swap_i += 1
              num[swap_i-1], num[pivot] = num[pivot], num[swap_i-1]  # 把基准值放中间
              pivot = swap_i - 1  # 此时基准值在中间
              if k == pivot:   # 左边正好是前k大数
                  return num[:k]
              elif k > pivot:  # 左边不足前k大数,去右边找
                  return self.findTopK(num, k, pivot + 1, r)
              else:             # 左边超过前k大数,去左边找
                  return self.findTopK(num, k, l, pivot - 1)

 295. 数据流的中位数 - 力扣(LeetCode)

  • 最小堆 + 最大堆

    • 参考K神题解
    • from heapq import *
      class MedianFinder:
          def __init__(self):
              self.A = []   # 小顶堆,保存较大的一半
              self.B = []   # 大顶堆,保存较小的一半
      
          def addNum(self, num: int) -> None:
              if len(self.A) != len(self.B):  # m > n,奇数,补充B
                  heappush(self.A, num)
                  heappush(self.B, -heappop(self.A))  # 淘汰下的最小值放到B里
              else:                           # m = n,偶数,补充A
                  heappush(self.B, -num)      
                  heappush(self.A, -heappop(self.B))  # 淘汰下的最大值放到A里
      
          def findMedian(self) -> float:
              if len(self.A) != len(self.B):  # m > n,奇数
                  return self.A[0]
              else:                           # m = n,偶数
                  return (self.A[0] - self.B[0]) / 2.0

后言

  • 学快排学了好久,脑子要炸掉了,另外想注册Claude发现接不了码注册不了了,可恶,浪费我学习时间,呸!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值