题目
你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
示例1
输入:
[[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] 中。
注意:
给定的列表可能包含重复元素,所以在这里升序表示 >= 。
1 <= k <= 3500
-105 <= 元素的值 <= 105
解法
nums中所有元素排序:0 4 5 9 10 12 15 18 20 22 24 26 30
元素来自哪个列表:1 0 2 1 0 1 0 2 1 2 0 0 2
代码
#include
#include
#include
#include
using namespace std;
class Solution {
public:
vector<int> smallestRange(vector<vector<int>>& nums) {
//放入数组中,并排序
int k = nums.size();//k个列表
vector<pair<int, int>> map;
for (int i=0;i<k;i++){
for(int j=0;j<nums[i].size();j++){
map.push_back({nums[i][j],i});
}
}
sort(map.begin(),map.end());
vector<int> flag(k);//标记区间中是否有k个列表中的元素
vector<int> ans;
int left = 0,n= map.size(),cnt=0;
int dif = INT_MAX;
//往右滑动窗口
for (int right = 0; right < n; right ++) {
//判断这个元素来自哪个列表,如第一次出现,标记在[left,right]区间中,这个列表中出现过元素了。
if (flag[map[right].second] == 0) cnt ++;
flag[map[right].second] ++;
//k个不同的列表中,每个列表中至少有一个元素在区间出现过了,寻找最小区间
while (cnt == k && left <= right) {
if (dif > map[right].first - map[left].first) {
dif = map[right].first - map[left].first;
ans = {map[left].first, map[right].first};
}
//向左移动
flag[map[left].second]--;
if(flag[map[left].second] == 0)
cnt--;
left++;
}
}
return ans;
}
};
int main()
{
vector<vector<int>> d(3, vector<int> ());
d[0] = {4,10,15,24,26};
d[1] = {0,9,12,20};
d[2] = {5,18,22,30};
Solution s;
vector<int> ans = s.smallestRange(d);
cout<<ans[0]<<" "<<ans[1];
return 0;
}
今天也是爱zz的一天哦!