373. Find K Pairs with Smallest Sums

You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k.

Define a pair (u,v) which consists of one element from the first array and one element from the second array.

Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums.

Example 1:

Input: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
Output: [[1,2],[1,4],[1,6]] 
Explanation: The first 3 pairs are returned from the sequence: 
             [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

Example 2:

Input: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
Output: [1,1],[1,1]
Explanation: The first 2 pairs are returned from the sequence: 
             [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

Example 3:

Input: nums1 = [1,2], nums2 = [3], k = 3
Output: [1,3],[2,3]
Explanation: All possible pairs are returned from the sequence: [1,3],[2,3]

改进:参考 https://leetcode.com/problems/find-k-pairs-with-smallest-sums/discuss/84551/simple-Java-O(KlogK)-solution-with-explanation

因为两个数组都是有序的,往min heap中添加元素的理想顺序应该是:首先只考虑两个数组的前k个元素,对应nums1中的某个元素,下一个理想顺序的组合应该是 nums1中的这个元素 + 从堆中poll出来的对应的nums2元素的下一个元素。堆中存index比较方便,先把(i, 0)放入堆中,i对应nums1的index,0是nums2的index;poll出来一个最小值之后,保存结果,检查index是否越界,然后把下一个candidate放入堆中

basic idea: use minHeap to keep track on next minimum pair sum, and we only need to maintain K possible candidates in the data structure.

for every numbers in nums1, its best candidate(yields min sum) always starts from nums2[0] since arrays are all sorted; and for a specific number in nums1, its next candidate sould be [this specific number] + nums2[current_associated_index + 1], unless out of boundary

时间:O(KlogK),空间:O(K)

class Solution {
    public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        List<int[]> res = new ArrayList<>();
        if(nums1.length == 0 || nums2.length == 0 || k == 0) return res;
        PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> (nums1[a[0]] + nums2[a[1]]) - (nums1[b[0]] + nums2[b[1]])); 
        // for(int i = 0; i < nums1.length && i < k; i++) {
        //     minHeap.offer(new int[] {i, 0});
        // }
        // while(k-- > 0 && !minHeap.isEmpty()) {
        //     int[] tmp = minHeap.poll();
        //     res.add(new int[] {nums1[tmp[0]], nums2[tmp[1]]});
        //     if(tmp[1] == nums2.length - 1)
        //         continue;
        //     minHeap.offer(new int[] {tmp[0], tmp[1] + 1});
        // }
        // return res;
        for(int i = 0; i < nums2.length && i < k; i++) {
            minHeap.offer(new int[] {0, i});
        }
        while(k-- > 0 && !minHeap.isEmpty()) {
            int[] tmp = minHeap.poll();
            res.add(new int[] {nums1[tmp[0]], nums2[tmp[1]]});
            if(tmp[0] == nums1.length - 1)
                continue;
            minHeap.offer(new int[] {tmp[0]+ 1, tmp[1]});
        }
        return res;
    }
}

之前的方法用了min heap,但类似于brute force,能过但是太慢了,O(K^2 logK)

class Solution {
    public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        List<int[]> res = new ArrayList<>();
        if(nums1 == null || nums2 == null) return res;
        PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> (b[0] + b[1]) - (a[0] + a[1]));
        int m = Math.min(nums1.length, k), n = Math.min(nums2.length, k);
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                minHeap.offer(new int[] {nums1[i], nums2[j]});
                if(minHeap.size() > k)
                    minHeap.poll();
            }
        }
        while(!minHeap.isEmpty()) {
            res.add(0, minHeap.poll());
        }
        return res;
    }
}

or

class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        List<List<Integer>> res = new ArrayList<>();
        if(nums1.length == 0 || nums2.length == 0 || k == 0) {
            return res;
        }
        PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> (nums1[a[0]] + nums2[a[1]]) - (nums1[b[0]] + nums2[b[1]]));
        boolean[][] visited = new boolean[nums1.length][nums2.length];
        minHeap.offer(new int[] {0, 0});
        visited[0][0] = true;
        
        for(int i = 0; i < k && !minHeap.isEmpty(); i++) {
            int[] cur = minHeap.poll();
            int r = cur[0], c = cur[1];
            
            List<Integer> tmp = new ArrayList<>();
            tmp.add(nums1[r]);
            tmp.add(nums2[c]);
            res.add(tmp);
            
            if(r + 1 < nums1.length && !visited[r + 1][c]) {
                minHeap.offer(new int[] {r + 1, c});
                visited[r + 1][c] = true;
            }
            if(c + 1 < nums2.length && !visited[r][c + 1]) {
                minHeap.offer(new int[] {r, c + 1});
                visited[r][c + 1] = true;
            }
        }
        
        return res;
    }
}
原文地址:https://www.cnblogs.com/fatttcat/p/9992881.html