- 可以在O(nlogn)的时间复杂度内完成排序
- 典型的用法是,寻找 第k个/前k个 最大/最小元素,k个有序序列合并
1.合并K个升序链表(最小堆实现)
或许可以改进成每次堆只存放K个元素?
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):def mergeKLists(self, lists):""":type lists: List[ListNode]:rtype: ListNode"""# 最小堆:根节点最小dummy = ListNode(-1)node = dummyheap = MinHeap()# 加入最小堆for ptr_l in lists:ptr = ptr_lwhile ptr is not None:heap.insert_node(ptr.val)ptr = ptr.nextwhile len(heap.array) > 1:temp_val = heap.delete_node()temp_node = ListNode(temp_val)node.next = temp_nodenode = temp_nodereturn dummy.nextclass MinHeap:def __init__(self):self.array = [-1]def insert_node(self, val):self.array.append(val)index = len(self.array) - 1while (index // 2 != 0):father = index // 2if self.array[father] > self.array[index]:temp = self.array[index]self.array[index] = self.array[father]self.array[father] = tempindex = fathercontinue# 未发生交换,完成插入breakdef delete_node(self):res = self.array[1]self.array[1] = self.array[-1]self.array = self.array[:-1]index = 1length = len(self.array)while (True):# 具有两个子节点if 2*index+1 <= length-1:left = self.array[index*2]right = self.array[index*2+1]if left < right:if self.array[index] > left:temp = self.array[index]self.array[index] = self.array[index*2]self.array[index*2] = tempindex = index * 2continueelse:breakelse:if self.array[index] > right:temp = self.array[index]self.array[index] = self.array[index*2+1]self.array[index*2+1] = tempindex = index * 2 + 1continueelse:break# 一个子节点elif 2*index <= length-1:if self.array[index] > self.array[index*2]:temp = self.array[index]self.array[index] = self.array[index*2]self.array[index*2] = tempindex = index * 2continueelse:break# 没有子节点else:breakreturn res
2.前K个高频元素
题目要求复杂度必须低于O(nlogn)。要寻找最大的K个值,可以用最小堆,并限制堆的大小为K
小于顶端的数被直接跳过,大于顶端的数则替换。这样的时间复杂度是O(nlogk)
class Solution(object):def topKFrequent(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]"""# 遍历存入字典->按频率排序最小堆抽出前k个 O(nlogn)"""topk (前k大)用小根堆,维护堆大小不超过 k 即可。每次压入堆前和堆顶元素比较,如果比堆顶元素还小,直接扔掉,否则压入堆。检查堆大小是否超过 k,如果超过,弹出堆顶。复杂度是 nlogk"""hash_dict = dict()for num in nums:if hash_dict.has_key(num):hash_dict[num] += 1else:hash_dict[num] = 1# 最小堆求最大的k个元素heap = MinHeap()res = []for key, val in hash_dict.items():if len(heap.array) < k + 1:heap.insert_node(val)res.append((key, val))elif val > heap.array[1]:val_to_delete = heap.delete_node()for i in range(k):if res[i][1] == val_to_delete:res.pop(i)breakheap.insert_node(val)res.append((key, val))for i in range(k):res[i] = res[i][0]return res