Solution to LeetCode 373 Find K Pairs with Smallest Sums.
LeetCode 373
Find K Pairs with Smallest Sums (Medium). [link]
Priority queue using min heap. Add the k pairs of first k of
nums1
with the first element ofnums2
((0,0), (1,0), … (k,0)) intopq
. Every time we pop out the first pair, push the pair with an increasednums2
(e.g. pop (0,0), push (0,1)).Time complexity O(k log k). It takes O(k) to select k pairs of numbers. It takes O(logk) time complexity when popping into the heap queue and adjust the order. Space complexity O(k). The
pq
only stores k pairs of numbers.
class Solution(object):
def kSmallestPairs(self, nums1, nums2, k):
"""
:type nums1: List[int]
:type nums2: List[int]
:type k: int
:rtype: List[List[int]]
"""
result = []
pq = [(nums1[i] + nums2[0], i, 0) for i in range(min(len(nums1), k))]
while pq and len(result) < k:
_, i, j = heappop(pq)
result.append([nums1[i], nums2[j]])
if j + 1 < len(nums2):
heappush(pq, (nums1[i] + nums2[j+1], i, j+1))
return result
Binary search. We aim to find the minimal sum of pairs
x
such that there are the number of pairs exceedk
. We can do binary search with a sliding window, because of the property of this problem:- If the sum of pairs is less than
x
, then the number of pairs is less thank
. - If the sum of pairs is not less than
x
, then the number of pairs is no less thank
.
After we get
x
, we add pairs with sum of them no more thanx
. Then we add pairs with sum of them equal tox
until the total number isk
.Time complexity O(k + (len(nums1) + len(nums2))* log (range(nums1) + range(nums2))). Binary search takes log (range(nums1) + range(nums2)) time complexity, where range(nums1) = max(nums1) - min(nums1). Sliding window for searching takes O(2 * (k + m + n). Space complexity O(1).
- If the sum of pairs is less than
class Solution(object):
def kSmallestPairs(self, nums1, nums2, k):
"""
:type nums1: List[int]
:type nums2: List[int]
:type k: int
:rtype: List[List[int]]
"""
l, r = nums1[0] + nums2[0], nums1[-1] + nums2[-1] + 1
while l < r: # binary search [l, r)
m = l + (r - l) // 2
count = 0
i, j = 0, len(nums2) -1
while i < len(nums1) and j >= 0: # sliding window
if nums1[i] + nums2[j] > m: # find minimized SUM
j -= 1
else:
count += j+1
i += 1
if count < k: # find kth smallest pairs SUM
l = m + 1
else:
r = m
SUM = l
result = []
# find pairs with the sum smaller than SUM
i = len(nums2) -1
for n1 in nums1:
while i >= 0 and n1 + nums2[i] >= SUM:
i -= 1 # find the smallest nums2
for j in range(i + 1):
result.append([n1, nums2[j]])
if len(result) == k:
return result
# find pairs with the sum equal to SUM (if len(result) < k)
i = len(nums2) - 1
for n1 in nums1:
while i >= 0 and n1 + nums2[i] > SUM:
i -= 1
j = i
while j >= 0 and n1 + nums2[j] == SUM:
result.append([n1, nums2[j]])
if len(result) == k:
return result
j -= 1
return result