You have k lists of sorted integers in non-decreasing order. Find the smallest range that includes at least one number from each of the k lists.
We define the range [a, b] is smaller than range [c, d] if b - a < d - c or a < c if b - a == d - c.
Example 1:
Input: nums = [[4,10,15,24,26],[0,9,12,20],[5,18,22,30]]
Output: [20,24]
Explanation:
List 1: [4, 10, 15, 24,26], 24 is in range [20,24].
List 2: [0, 9, 12, 20], 20 is in range [20,24].
List 3: [5, 18, 22, 30], 22 is in range [20,24].
Example 2:
Input: nums = [[1,2,3],[1,2,3],[1,2,3]]
Output: [1,1]
Constraints:
- nums.length == k
- 1 <= k <= 3500
- 1 <= nums[i].length <= 50
- -105 <= nums[i][j] <= 105
- nums[i] is sorted in non-decreasing order.
整体来说是用 merge sort 的方式
用一个 min heap 来维护最终答案中所有的数字, 每次从 heap 中 pop 出最小值, 将该数字所在 list 中的下一个数字 push 进 heap 中, 此时 range 中的最小值是 heap 中 top 的值, 最大值有可能是刚刚 push 进去的那个值, 我们只需要用原有的最大值与该值进行比较即可。
use std::cmp::Reverse;
use std::collections::BinaryHeap;
impl Solution {
pub fn smallest_range(nums: Vec<Vec<i32>>) -> Vec<i32> {
let mut ans;
let mut min = i32::MAX;
let mut max = i32::MIN;
let mut heap = BinaryHeap::new();
let mut pointers = vec![0; nums.len()];
for (i, row) in nums.iter().enumerate() {
min = min.min(row[0]);
max = max.max(row[0]);
heap.push(Reverse((row[0], i)));
}
ans = vec![min, max];
loop {
let Reverse((_, i)) = heap.pop().unwrap();
pointers[i] += 1;
if pointers[i] == nums[i].len() {
break;
}
heap.push(Reverse((nums[i][pointers[i]], i)));
min = heap.peek().unwrap().0 .0;
max = max.max(nums[i][pointers[i]]);
if max - min < ans[1] - ans[0] {
ans = vec![min, max];
}
}
ans
}
}