题意:
你有 k 个 非递减排列 的整数列表。找到一个 最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
示例 1:
输入:nums = [[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] 中。
数据范围:
nums.length == k
1 <= k <= 3500
1 <= nums[i].length <= 50
-1e5 <= nums[i][j] <= 1e5
nums[i] 按非递减顺序排列
解法:
将a[i][j]变成二元组(a[i][j],i).
那么问题变为:
找到一个长度最小的区间[l,r],
满足这个区间内每个序列都至少有一个二元组在里面.
将所有二元组放在一起排序,
然后枚举r,找到一个最大的l,满足[l,r]符合上面条件.
发现l可以双指针维护,那么这题就做完了.
同时,l和r的取值是离散的,因为肯定是数组中出现过的数,
所以只需要枚举出现过的数即可.
code:
class Solution {
public:
#define PI pair<int,int>
vector<int> smallestRange(vector<vector<int>>& a) {
int n=a.size();
vector<int>ans;
int milen=2e5+10;
vector<PI>temp;
for(int i=0;i<n;i++){
int m=a[i].size();
for(int j=0;j<m;j++){
temp.push_back({a[i][j],i});
}
}
sort(temp.begin(),temp.end());
map<int,int>mp;
int sum=0;
int l=0;
for(int i=0;i<temp.size();i++){
if(++mp[temp[i].second]==1)sum++;
while(sum==n){
if(temp[i].first-temp[l].first+1<milen){
milen=temp[i].first-temp[l].first+1;
ans={temp[l].first,temp[i].first};
}
if(--mp[temp[l++].second]==0)sum--;
}
}
return ans;
}
};