632. Smallest Range
You have k lists of sorted integers in ascending 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:[[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].
Note:
- The given list may contain duplicates, so ascending order means >= here.
- 1 <= k <= 3500
- -105 <= value of elements <= 105.
- For Java users, please note that the input type has been changed to List<List>.
- And after you reset the code template, you’ll see this point.
方法1: priority_queue
官方题解:https://leetcode.com/problems/smallest-range/solution/
思路:
官方题解第三种方法将思路讲的很清楚。首先我们每个stream取一个点,确定了min 和 max,也有了range,接下来如何缩小range?max现在不能减小,所以选择增大min。找到min所在的stream,向前推进一个,再次比较找到新的min,和max。注意,这个找min和max的过程如果用pointer的方法,需要O(k),但是如果用priority queue,只需要o(logk)。对于min我们需要知道取到最小以后,如何向前推进,所以还要同时记录该数字来自哪条stream,以及它当前所处的index。在这里将{num , i} 组成pair存在pq里一起排序,而用一个k长度的vector记录每条steam行进到的index。其他的方法还可能使用iterator。对于max来讲,每一次我们并不会直接推进,而是被动的被下一次pop出来的数字不断向上拉,所以用一个int mx,来max(mx,newpopped)就可以。
易错点:
- 当任何一条stream结束之后,搜索可以结束。
Complexity
Time complexity: O(n log k)
Space complexity: O(k)
class Solution {
public:
vector<int> smallestRange(vector<vector<int>>& nums) {
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
int k = nums.size();
vector<int> result(2, 0);
vector<int> pt(k, 0);
int mx = INT_MIN;
int range = INT_MAX;
for (int i = 0; i < k; i++) {
//if (nums[i].empty()) return {};
q.push({nums[i][0], i});
mx = max(mx, nums[i][0]);
}
while (true) {
int mn = q.top().first;
int i = q.top().second;
q.pop();
if (mx - mn < range) {
range = mx - mn;
result[0] = mn;
result[1] = mx;
}
if (pt[i] == nums[i].size() - 1) break;
pt[i]++;
mx = max(mx, nums[i][pt[i]]);
q.push({nums[i][pt[i]], i});
}
return result;
}
};