leetcode-堆

掘金

堆、堆排序和优先队列的那些事 - 心谭小站 - 博客园

力扣

课程简介 - Python 数据结构与算法视频教程

堆排序分为2个步骤

首先是构建大顶锥,然后从数组尾部开始便利,把大顶锥的顶点和尾部交换,就得到了一个由小到大的数组。

三分钟玩转堆排序原理及面试题(多图解释 Python实现)_码农富哥-CSDN博客

LeetCode—Python—215. 数组中的第K个最大元素(快排、堆排序)_IOT_victor的博客-CSDN博客

堆排序的两种方法实现(Python)以及面试中关于堆排序的相关题目_Matrix_cc的博客-CSDN博客

347. 前 K 个高频元素

手写堆

前k个高频元素

堆排序的两种方法实现(Python)以及面试中关于堆排序的相关题目_Matrix_cc的博客-CSDN博客

class Solution(object):
    import heapq
    def push(self,value_key,min_heap,k):
        if len(min_heap)<k:
            #构造大小为k的堆
            heapq.heappush(min_heap,value_key)
        else:
            if value_key[0]<min_heap[0][0]:
                pass
            else:
                #pop出堆顶元素
                min_value,min_key = heapq.heappop(min_heap)
                #push进当前元素
                heapq.heappush(min_heap,value_key)
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        #分为2步,
        #首先存成一个map,然后建立一个大小为k的堆,堆排序时间复杂度是o(nlogn)
        #第一步:哈希表o(n)
        dic={}
        for i in range(len(nums)):
            if nums[i] in dic:
                dic[nums[i]]+=1
            else:
                dic[nums[i]]=1
        #第二步:堆排序o(nlogn)。
        #先把前k个元素放进去,然后后面的元素依次与堆顶元素进行比较
        min_heap=[]
        for key in dic.keys():
            value=dic[key]
            self.push((value,key),min_heap,k)
        #取出来k 
        res=[]
        for i in range(k):
            res.append(min_heap[i][1])
        return res

数据流中的中位数

手写堆(我)

参考

堆排序的两种方法实现(Python)以及面试中关于堆排序的相关题目_Matrix_cc的博客-CSDN博客

def shiftdown(nums,root,n):
    while 2*root+1<n:
        child=2*root+1
        if child+1<n and nums[child+1]>nums[child]:
            child=child+1
        if nums[root]>=nums[child]:
            break
        nums[root],nums[child]=nums[child],nums[root]
        root=child
def heapify(nums):
    n=len(nums)
    for i in range(n//2,-1,-1):
        shiftdown(nums,i,n)
def heapsort(nums):
    heapify(nums)
    n=len(nums)
    for i in range(n-1):
        nums[0],nums[n-i-1]=nums[n-i-1],nums[0]
        shiftdown(nums,0,n-i-1)
nums=[5,2,3,1,8]
heapsort(nums)
print(nums)

会议室

347 前k个高频元素

class Solution(object):
    def push(self,val,minheap,k):
        #用python的heap包构建堆
        #如果堆列表的长度小于k,直接将值插入列表
        if len(minheap)<k:
            heapq.heappush(minheap,val)
        else:
            #如果堆列表长度大于k,如果val小于锥顶元素,跳过(肯定不是前k大)
            if val[0]<=minheap[0][0]:
                pass
            else:
                heapq.heapreplace(minheap, val)
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        # minheap=[]
        # for i in range(len(nums)):
        #     self.push(nums[i],minheap,k)
        #minheap就是前k大
        dic={}
        for i in range(len(nums)):
            dic[nums[i]]=dic.get(nums[i],0)+1
        minheap=[]
        for key in dic:
            # self.push((key,dic[key]),minheap,k)
            self.push((dic[key],key),minheap,k)
        res=[]
        for i in range(k):
            res.append(minheap[i][1])
        return res
        
class Solution(object):
    import heapq
    def push(self,value_key,min_heap,k):
        if len(min_heap)<k:
            #构造大小为k的堆
            heapq.heappush(min_heap,value_key)
        else:
            if value_key[0]<min_heap[0][0]:
                pass
            else:
                #pop出堆顶元素
                min_value,min_key = heapq.heappop(min_heap)
                #push进当前元素
                heapq.heappush(min_heap,value_key)
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        #分为2步,
        #首先存成一个map,然后建立一个大小为k的堆,堆排序时间复杂度是o(nlogn)
        #第一步:哈希表o(n)
        dic={}
        for i in range(len(nums)):
            if nums[i] in dic:
                dic[nums[i]]+=1
            else:
                dic[nums[i]]=1
        #第二步:堆排序o(nlogn)。
        #先把前k个元素放进去,然后后面的元素依次与堆顶元素进行比较
        min_heap=[]
        for key in dic.keys():
            value=dic[key]
            self.push((value,key),min_heap,k)
        #取出来k 
        res=[]
        for i in range(k):
            res.append(min_heap[i][1])
        return res

295. 数据流的中位数

import heapq

class MedianFinder(object):
    def __init__(self):
        """
        initialize your data structure here.
        """
        #用一个最大堆,一个最小堆。
        #最大堆表示排序之后的list左边,最小堆表示排序之后的list右边。因为我们需要的是堆顶元素。
        self.maxheap=[]
        self.minheap=[]
        #python heap表示的是最小堆,取个负数就是最大堆了。
    def addNum(self, num):
        """
        :type num: int
        :rtype: None
        """
        #先把元素添加到最大堆里面(最大堆是左半部分)
        heapq.heappush(self.maxheap,-num)
        #把最大堆中的最大元素添加到最小堆中
        #先从最大堆中弹出堆顶元素
        max_heap_top=heapq.heappop(self.maxheap)
        #把最大堆中的堆顶元素加入最小堆
        heapq.heappush(self.minheap,-max_heap_top)
        #如果最小堆中的元素比最大堆多,则把最小堆中的最小元素移动到最大堆
        if len(self.minheap)>len(self.maxheap):
             min_heap_top = heapq.heappop(self.minheap)
             heapq.heappush(self.maxheap, -min_heap_top)
    def findMedian(self):
        """
        :rtype: float
        """
        if len(self.maxheap)>len(self.minheap):
            return - self.maxheap[0]
        else:
            return (-self.maxheap[0]+self.minheap[0])/2
        
obj = MedianFinder()
obj.addNum(1)
obj.addNum(2)
param_2 = obj.findMedian()
print(param_2)

215 数组中第k大元素

class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        #最大堆遍历到第k个
        #用最小堆来代替(对num取负数)
        maxheap=[]
        for i in range(len(nums)):
            heapq.heappush(maxheap,-nums[i])
        for i in range(k):
            maxval=heapq.heappop(maxheap)
        return -maxval

253 会议室

23 合并k个有序链表

# 思路:每个链表的第一个结点入堆,进行比较
# 最小的出堆,然后找出堆链表中的后续入堆
# 在python3的堆中链表无法比较大小,我们传入的是val和他所在的list(这是第几个链表)方便查找后续
from heapq import *
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        minHeap = []
        for index, node in enumerate(lists): # index 用来记录这是第几个链表, node 是每个链表的头结点
                if node != None:  # 只要头结点不空
                    heappush(minHeap ,(node.val, index)) # 将当前头结点的value以及该头结点所在的链表index入堆
        linkedlistHead = ListNode(-1) # 创建用来存放结果的链表
        linkedlistTail = linkedlistHead          # 这个是尾结点        
        while minHeap:  
            val, index = heappop(minHeap) # 堆内链表value最小的出堆,找到他是第几个链表,好找他的下一个位置
            linkedlistTail.next = lists[index]       # 加入到了结果集合中
            linkedlistTail = linkedlistTail.next                # 开始加下一个位置
            lists[index] = lists[index].next # 找到当前链表的下一个元素
            if lists[index] != None:      # 如果不空的话就让他入堆
                heappush(minHeap, (lists[index].val, index)) # 下一个元素入堆
        return linkedlistHead.next # 返回链表

作者:Fight_for_your_life
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/lc23-he-bing-kge-sheng-xu-lian-biao-by-fight_for_y/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        import heapq
        dummy = ListNode(0)
        p = dummy
        head = []
        for i in range(len(lists)):
            if lists[i] :
                heapq.heappush(head, (lists[i].val, i))
                lists[i] = lists[i].next
        while head:
            val, idx = heapq.heappop(head)
            p.next = ListNode(val)
            p = p.next
            if lists[idx]:
                heapq.heappush(head, (lists[idx].val, idx))
                lists[idx] = lists[idx].next
        return dummy.next

373. 查找和最小的K对数字

class Solution:
    def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
        """
        题目要求:从两个有序数组中每次选出一个元素,组成数对,返回两者相加之和前k个最小的数对并返回
        :param nums1: 第一个有序的数组
        :param nums2: 第二个有序的数组
        :param k: 前k个最小的数对
        :return: 返回前k小的每一个数对
        """
        # 解题思路:暴力法很简单了,把所有的数对都找到并排序,然后返回TopK即可(可能会超时,你可以试试)
        # 显然本题并不是想让我们用暴力法解决,通过常识和观察不难发现,最小的数对一定为(num1[0],num2[0]),第二小的必为(num1[0],num2[1])和(num1[1],num2[0])其中一个
        # 依此类推,可以发现规律,对于当前选择的最小数对(num1[i],num2[j]),其下一个最小的数对必为(num1[i],num2[j+1])和(num1[i+1],num2[j])其中一个
        # 接着就很容易形成一个基本的思路,用一个最小堆维护待选择的数对(以相加之和为排序准则)
        # 每次选出当前最小数对(num1[i],num2[j])的同时将(num1[i],num2[j+1])和(num1[i+1],num2[j])一起进堆,直到拿到k个最小数对为止
        # 但要注意,这个基本思路存在一个缺陷,就是可能会有重复进堆的数对
        # 例如:当前最小数对为(num1[0],num2[1]),此时(num1[1],num2[1])和(num1[0],num2[2])进堆
        # 接着下一个最小的数对若为(num1[1],num2[0]),此时此时(num1[1],num2[1])和(num1[2],num2[0])进堆,可以发现(num1[1],num2[1])重复进堆
        # 显然会影响答案的准确性,至于如何处理有两种思路,最简单且容易理解的就是设置一个标记集合,标记数对是否进过堆,没进过才进堆
        # 此思路对应解答如下:
        n, m = len(nums1), len(nums2)
        res = []  # 返回结果的列表
        # 初始化小根堆,并将(num1[0]+num2[0],0,0)进堆(保留两者的下标,方便后面操作),默认以第一个元素大小为排序准则(即这里的两者之和)
        # 当然也可以自定义排序规则(有兴趣可以了解,不展开,多啰嗦一句,一些特殊的题可能必须要自定义排序规则,不过很少见,你可以忽略)
        heap = [(nums1[0] + nums2[0], 0, 0)]
        visited = set()  # 标记集合
        while heap and len(res) < k:
            _, i, j = heapq.heappop(heap)
            if (i, j) in visited:  # 进过堆直接跳过
                continue
            visited.add((i, j))  # 标记该位置进过堆
            res.append([nums1[i], nums2[j]])  # 记录当前最小数对
            # i, j没有越界,就将(num1[i],num2[j+1])和(num1[i+1],num2[j])一起进堆
            if i + 1 < n:
                heapq.heappush(heap, (nums1[i + 1] + nums2[j], i + 1, j))
            if j + 1 < m:
                heapq.heappush(heap, (nums1[i] + nums2[j + 1], i, j + 1))
        return res  # 返回结果

        # 另一种非常巧妙的思路去解决重复进堆的问题,不如第一种思路那么直接,但是时间空间上要比第一种思路略好(可以击败100%,但总体上是同一量级上的)
        # 我们将两个数组看作一个二维表格更好理解(自己画画看),比当前数对小的必然是它左侧或者下侧的其中一个(品一品应该很简单)
        # 在分析为什么会出现重复进堆的时候,我们发现重复是因为选择下一个最小数对时有左和下两种选择,如果只有一个方向的选择的话,不就不会重复了么
        # 这个思路主要是从这个角度出发思考问题,可以将num1的前k个索引数对(0,0),(1,0),…,(k−1,0)直接一起进堆
        # 每次从堆中取出数对(num1[i],num2[j])时,只需要将num2索引j增加即可,这样就避免了重复加入元素的问题。
        # n, m = len(nums1), len(nums2)
        # res = []
        # # 初始化小根堆,将num1的前k个索引数对全部进堆(注意num1长度不够k的话,就取其长度即可)
        # heap = [(nums1[i] + nums2[0], i, 0) for i in range(min(n, k))]
        # while heap and len(res) < k:
        #     _, i, j = heapq.heappop(heap)
        #     res.append([nums1[i], nums2[j]])
        #     # j不越界,只需要将(num1[i],num2[j+1])进堆即可
        #     if j + 1 < m:
        #         heapq.heappush(heap, (nums1[i] + nums2[j + 1], i, j + 1))
        # return res

作者:sqsx
链接:https://leetcode-cn.com/problems/find-k-pairs-with-smallest-sums/solution/dui-you-xian-dui-lie-de-ying-yong-liang-5v66b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

元祖可以直接比较大小啊,用第一个元素去比较

这个题也是广搜, 队列不需要遍历完就能出结果就是广搜。

除了接鸡蛋这种判断大小的动态规划,其他的动态规划都可以用记忆化深搜解决

dfs就是递归,bfs就是循环。

class Solution(object):
    def kSmallestPairs(self, nums1, nums2, k):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :type k: int
        :rtype: List[List[int]]
        """
        #堆排序+广度优先遍历
        import heapq
        deq=[]
        heapq.heappush(deq,(nums1[0]+nums2[0],0,0))
        count=0
        visited=set()
        visited.add((0,0))
        res=[]
        while count<k and deq:
            #弹出堆顶最小元素
            _,i,j=heapq.heappop(deq)
            res.append([nums1[i],nums2[j]])
            count=count+1
            #下一组
            if i+1<len(nums1) and j<len(nums2) and (i+1,j) not in visited:
                heapq.heappush(deq,(nums1[i+1]+nums2[j],i+1,j))
                visited.add((i+1,j))
            if i<len(nums1) and j+1<len(nums2) and (i,j+1) not in visited:
                heapq.heappush(deq,(nums1[i]+nums2[j+1],i,j+1))
                visited.add((i,j+1))
        return res

6155. 找出数组的第 K 大和

贪心+子序列+堆

 

class Solution:
    def kSum(self, nums: List[int], k: int) -> int:
        n = len(nums)
        maxSum = 0
        for i in range(n):
            if nums[i] > 0:
                maxSum += nums[i]
            nums[i] = abs(nums[i])
        nums.sort()
        import heapq
        heap = []
        heapq.heappush(heap, (0, 0))
        for i in range(k - 1):
            x, y = heapq.heappop(heap)
            if y != n:
                heapq.heappush(heap, (x + nums[y], y + 1))
                if y:
                    heapq.heappush(heap, (x + nums[y] - nums[y - 1], y + 1))
        x, y = heapq.heappop(heap)
        return maxSum - x

作者:worcester_
链接:https://leetcode.cn/problems/find-the-k-sum-of-an-array/solution/python3zhuan-hua-wei-di-kxiao-zi-xu-lie-cye84/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值