【力扣hot100】刷题笔记Day22

前言

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

912. 排序数组 - 力扣(LeetCode)

  • 快速排序(数组法):时间O(nlogn),空间O(n)

    • def quick_sort(arr):
          if len(arr) <= 1:   # 递归结束
              return arr
          else:
              pivot = random.choice(arr)  # 随机选择基准值
              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)  # 重新组合
      
      
  • 快速排序(原地挖坑交换法):时间O(nlogn),空间O(1)

    • 【力扣hot100】刷题笔记Day22_第1张图片
    • class Solution:
          def sortArray(self, nums: List[int]) -> List[int]:
              n = len(nums)
      
              def quick(left, right):
                  if left >= right:
                      return
                  pivot_index = random.randint(left, right)
                  nums[left], nums[pivot_index] = nums[pivot_index], nums[left]
                  pivot = left
                  i = left
                  j = right
                  while i < j:
                      while i < j and nums[j] > nums[pivot]:   # 从右到左第一个小于等于pivot的数
                          j -= 1
                      while i < j and nums[i] <= nums[pivot]:  # 从左到右第一个大于pivot的数
                          i += 1
                      nums[i], nums[j] = nums[j], nums[i]  # 互换,使得pivot左边小于等于,右边大
                  nums[pivot], nums[j] = nums[j], nums[pivot]  # 此时i=j,填充pivot在中间
                  if j == right:  # 优化重复元素,j没动说明pivot取的最大,其他数都<=pivot
                      while j > 0 and nums[j]==nums[j-1]:  # 减少重复的最大右边界
                          j -= 1
                      quick(left, j-1)  # 只需排序左边
                  else:
                      quick(left, j - 1)  # pivot左边递归排序
                      quick(j + 1, right)  # pivot右边递归排序
      
              quick(0, n - 1)
              return nums

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)

    • 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(big) + len(equal):  
                      return quick_sort(small, k - len(big) - len(equal))  # 递归进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发现接不了码注册不了了,可恶,浪费我学习时间,呸!

你可能感兴趣的:(力扣hot100刷题笔记,leetcode,笔记,算法,职场和发展,数据结构)