22.Jan.14 多路归并合集

(1) 21. 合并两个有序链表(易)

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

思路: 遍历两个链表,谁小要谁

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if not l1 and not l2:
            return
        dumy = new = ListNode(0)        #注意要一个虚拟结点
        while l1 and l2:
            if l1.val<l2.val:
                new.next=l1
                l1=l1.next
            else:
                new.next=l2
                l2=l2.next
            new = new.next
        if not l1:                      #接上后面的
            new.next=l2
        if not l2:
            new.next=l1
        return dumy.next

(2) 23. 合并K个排序链表(难)

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6

思路: 遍历每一个链表,把每个节点的value压入最小堆。然后从最小堆循环pop出value重新构建新链表。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        import heapq
        hpq = list()
        for l in lists:
            while l:
                heapq.heappush(hpq, l.val)
                l = l.next
        head = new = ListNode()
        while hpq:
            new.next = ListNode(heapq.heappop(hpq))
            new = new.next
        return head.next

(3) 88. 合并两个有序数组(易)

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n。

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]

思路:
方法一:常规双指针,类似题(1)
方法二:倒序双指针,把最大的放入nums1末尾,因为最后需要返回的是nums1。

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        i = m-1
        j = n-1
        res = m + n - 1
        while res >= 0:
            if i >= 0 and j >= 0:
                if nums1[i] >= nums2[j]:
                    nums1[res] = nums1[i]
                    i -= 1
                else:
                    nums1[res] = nums2[j]
                    j -= 1
            elif j >= 0:
                nums1[res] = nums2[j]
                j -= 1
            res -= 1

(3) 378. 有序矩阵中第K小的元素(中)

给定一个 n x n 矩阵,其中每行和每列元素均按升序排序(相邻元素可能相等),找到矩阵中第k小的元素。

请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。

matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。

思路: 大根堆(负数小根堆)保持堆中含有k个数。

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        n = len(matrix)
        hpq = list()
        for i in range(n):
            for j in range(n):
                if len(hpq) < k:
                    heapq.heappush(hpq, -matrix[i][j])
                elif -hpq[0] > matrix[i][j]:
                    heapq.heappop(hpq)
                    heapq.heappush(hpq, -matrix[i][j])
        return -hpq[0]

(4) 632. 最小区间(难)

你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。

我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

输入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
输出: [20,24]
解释:
列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。
列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。
列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。

逃(w)

(5) 373. 查找和最小的K对数字(中)

给定两个以升序排列的整数数组 nums1 和 nums2 , 以及一个整数 k。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。

请找到和最小的 k 个数对 (u1,v1), (u2,v2) … (uk,vk)。

输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

思路: 先把nums1中所有元素和nums2首元素的组合放进堆中(包括下标),然后下一轮把nums1中所有元素和nums2第二个元素的组合放进堆中,以此类推。一共进行k轮,每轮将堆顶元素加入结果数组。

class Solution:
    def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
        m, n = len(nums1), len(nums2)
        ans = []
        pq = [(nums1[i] + nums2[0], i, 0) for i in range(min(k, m))]
        heapq.heapify(pq)
        while pq and k:
            _, i, j = heapq.heappop(pq)
            ans.append([nums1[i], nums2[j]])
            if j < len(nums2) - 1:
                heapq.heappush(pq, (nums1[i] + nums2[j+1], i, j+1))
            k -= 1
        return ans

(6) 786. 第 K 个最小的素数分数(难)

素数一般指质数,质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
给你一个按递增顺序排序的数组 arr 和一个整数 k 。数组 arr 由 1 和若干 素数 组成,且其中所有整数互不相同。

对于每对满足 0 <= i < j < arr.length 的 i 和 j ,可以得到分数 a r r [ i ] / a r r [ j ] arr[i] / arr[j] arr[i]/arr[j]

那么第 k 个最小的分数是多少呢? 以长度为 2 的整数数组返回你的答案, 这里 a n s w e r [ 0 ] = = a r r [ i ] answer[0] == arr[i] answer[0]==arr[i] a n s w e r [ 1 ] = = a r r [ j ] answer[1] == arr[j] answer[1]==arr[j]

输入:arr = [1,2,3,5], k = 3
输出:[2,5]
解释:已构造好的分数,排序后如下所示:
1/5, 1/3, 2/5, 1/2, 3/5, 2/3
很明显第三个最小的分数是 2/5

思路: 和(5)一样。最后返回的是结果数组的最后一个元素。

class Solution:
    def kthSmallestPrimeFraction(self, arr: List[int], k: int) -> List[int]:
        m = len(arr)
        rev = arr[::-1]
        pq = [(arr[i]/rev[0], i, 0) for i in range(m)]
        res = list()
        heapq.heapify(pq)
        while k:
            _, i, j = heapq.heappop(pq)
            res.append([arr[i], rev[j]])
            if j < m - 1:
                heapq.heappush(pq, (arr[i]/rev[j+1], i, j+1))
            k -= 1
        return res[-1]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值