经典算法 | 给定n个集合,求解一个范围,使得这个范围包含每个集合至少m个数
2018-01-18 17:51
316 查看
这题给你许多个数组,让你给出一个范围,这个范围里面包含每个数组至少一个数,并且使这个范围尽可能的小。
使得这个范围里面包含每个数组至少m个数也可以适用相同的方法解决,只需要修改一个值就行了。
这题是使用贪心算法的思想解决的。
首先把所有数组里面的值都混合在一起,组成一个数组theMark,然后排序,混合之后的数组为pair类型的数组,pair第一个值表示得到的这个值属于几号数组,第二个值才真正表示假如混合数组的这个数的值
使用两个值left和right,isGet[i]用来记录left和right之间的所有数包含了i号数组里面多少个值,使用k表示left和right之间包含了多少个区间,
设区间总数为n
算法首先right不断向右,直到找到第一个left和right区间使得left和right之间包含了所有区间至少一个值,然后left不断向右,直到left在向右一格k将小于n,这个时候left和right之间的范围就是theMark[0]到theMark[right]之间所有可能包含n个组的范围里面最小的一个,这个时候theMark[0]到theMark[right]之间包含全部n个组的最小范围就得到了,right记录的是这个组的右端,left记录的是最后一个加以判定的组的左端,
Left往右一步然后right继续往右,当left到right之间k不为n的时候,这个时候theMark[0]到theMark[right]之间不会得到比之前得到的范围(也就是前一个left到right这个范围)更好的范围,维持现状不变,这个时候theMark[0]到theMark[right]包含全部n个组的最小范围处于得到状态,left记录的是最后一个加以判定的组的左端,因此right继续往右
当left到right之间的k为n的时候,left和right之间可能得到一个右端为right的比之前的所有范围都要好的范围,因此left不断往右,直到下一步k<n,比较这个范围是否有已经有的最好范围要好,判定完成之后这个时候theMark[0]到theMark[right]包含全部n个组的最小范围处于得到状态,left记录的是最后一个加以判定的组的左端,right继续往右
直到right等于数组的最右端,这个时候theMark数组里面全部的数字中包含全部n个组的最小范围处于得到状态,left记录的是最后一个加以判定的组的左端,这个时候被记录的组就是最小的范围
本题的思路还适用求一个集合,使得这个集合包含每个集合至少一个数,使得集合里面的数最少,或者是求一个范围,使得这个范围包含每个集合至少一个数,使得这个范围里面的数最少class Solution {
public:
static bool cmp(pair<int, int> & a, pair<int, int> &b)
{
return a.second < b.second;
}
vector<int> smallestRange(vector<vector<int>>& nums) {
vector<pair<int, int>> theMark;
int theAllG = nums.size();
vector<int> isGet(nums.size(), 0);
for(int i=0;i<nums.size();i++)
for (int j = 0; j < nums[i].size(); j++)
{
theMark.push_back(pair<int, int>(i, nums[i][j]));
}
sort(theMark.begin(), theMark.end(), cmp);
int left, right,k;
int n = theMark.size();
left = 0; right = 0; k = 0;
vector<int> result; int theMinLength=1000000;
while (right != n)
{
if (isGet[theMark[right].first] == 0)
{
k++;
}
isGet[theMark[right].first]++;
if (k == theAllG)
{
while (k == theAllG)
{
if(isGet[theMark[left].first]==1)
{
k--;
}
isGet[theMark[left].first]--;
left++;
}
int a, b;
a = theMark[left - 1].second; b = theMark[right].second;
if (b - a < theMinLength)
{
theMinLength = b - a;
result.clear();
result.push_back(a); result.push_back(b);
}
}
right++;
}
return result;
}
};
使得这个范围里面包含每个数组至少m个数也可以适用相同的方法解决,只需要修改一个值就行了。
这题是使用贪心算法的思想解决的。
首先把所有数组里面的值都混合在一起,组成一个数组theMark,然后排序,混合之后的数组为pair类型的数组,pair第一个值表示得到的这个值属于几号数组,第二个值才真正表示假如混合数组的这个数的值
使用两个值left和right,isGet[i]用来记录left和right之间的所有数包含了i号数组里面多少个值,使用k表示left和right之间包含了多少个区间,
设区间总数为n
算法首先right不断向右,直到找到第一个left和right区间使得left和right之间包含了所有区间至少一个值,然后left不断向右,直到left在向右一格k将小于n,这个时候left和right之间的范围就是theMark[0]到theMark[right]之间所有可能包含n个组的范围里面最小的一个,这个时候theMark[0]到theMark[right]之间包含全部n个组的最小范围就得到了,right记录的是这个组的右端,left记录的是最后一个加以判定的组的左端,
Left往右一步然后right继续往右,当left到right之间k不为n的时候,这个时候theMark[0]到theMark[right]之间不会得到比之前得到的范围(也就是前一个left到right这个范围)更好的范围,维持现状不变,这个时候theMark[0]到theMark[right]包含全部n个组的最小范围处于得到状态,left记录的是最后一个加以判定的组的左端,因此right继续往右
当left到right之间的k为n的时候,left和right之间可能得到一个右端为right的比之前的所有范围都要好的范围,因此left不断往右,直到下一步k<n,比较这个范围是否有已经有的最好范围要好,判定完成之后这个时候theMark[0]到theMark[right]包含全部n个组的最小范围处于得到状态,left记录的是最后一个加以判定的组的左端,right继续往右
直到right等于数组的最右端,这个时候theMark数组里面全部的数字中包含全部n个组的最小范围处于得到状态,left记录的是最后一个加以判定的组的左端,这个时候被记录的组就是最小的范围
本题的思路还适用求一个集合,使得这个集合包含每个集合至少一个数,使得集合里面的数最少,或者是求一个范围,使得这个范围包含每个集合至少一个数,使得这个范围里面的数最少class Solution {
public:
static bool cmp(pair<int, int> & a, pair<int, int> &b)
{
return a.second < b.second;
}
vector<int> smallestRange(vector<vector<int>>& nums) {
vector<pair<int, int>> theMark;
int theAllG = nums.size();
vector<int> isGet(nums.size(), 0);
for(int i=0;i<nums.size();i++)
for (int j = 0; j < nums[i].size(); j++)
{
theMark.push_back(pair<int, int>(i, nums[i][j]));
}
sort(theMark.begin(), theMark.end(), cmp);
int left, right,k;
int n = theMark.size();
left = 0; right = 0; k = 0;
vector<int> result; int theMinLength=1000000;
while (right != n)
{
if (isGet[theMark[right].first] == 0)
{
k++;
}
isGet[theMark[right].first]++;
if (k == theAllG)
{
while (k == theAllG)
{
if(isGet[theMark[left].first]==1)
{
k--;
}
isGet[theMark[left].first]--;
left++;
}
int a, b;
a = theMark[left - 1].second; b = theMark[right].second;
if (b - a < theMinLength)
{
theMinLength = b - a;
result.clear();
result.push_back(a); result.push_back(b);
}
}
right++;
}
return result;
}
};
相关文章推荐
- 给定n个数组编号1~n,给定一个范围,使得这个范围包含第k个数组至少ak个数的算法
- 一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数
- 一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数。
- 求k个数组包含每个数组至少一个元素的最小范围(待字闺中,备忘)
- 一个只由字母数字字符和破折号组成的字符串S. 该字符串被N个破折号分成N + 1个组。 给定数字K,使得每个组包含完全K个字符,除了第一个组可能少于K
- 一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数
- 给定包含4300000000个32位整数的顺序文件,如何找出一个出现至少两次的整数
- 给定一个实数数组,按序排列(从小到大),从数组从找出若干个数,使得这若干个数的和与M最为接近,描述一个算法,并给出算法的复杂度。
- 经典算法 | 给定n个矩形,判断这些矩形是否在不重合的情况下组成一个大矩形的算法
- 整型数组处理算法(九)给定任意一个正整数,求比这个数大且最小的“不重复数”(性能优化)[2014百度笔试题]
- 给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次,编写代码找出数组中的某个元素
- 描述一个运行时间为Θ(nlgn)的算法,给定n个整数的集合S和另一个整数x,该算法能确定S中是否存在两个其和刚好为x的元素
- List的All方法使用问题:我用List1的All方法来确保List1的所有每个数组元素中是否包含Arr1中的任意元素,这个部分很难实现。 因为,没有一个数组中是否包含另一个数组中的任意元素这个功能
- 正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项
- 给定一个实数数组,按序排列(从小到大),从数组从找出若干个数,使得这若干个数的和与M最为接近,描述一个算法,并给出算法的复杂度。
- 一个长度为N的整形数组,数组中每个元素的取值范围是[0,N-1],写一个算法判断数组中是否存在重复的数字
- 已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。 给定一个int数组A,同时给定
- 给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。
- 给定一个排序后的数组,包含n个整数,但这个数组已被旋转过多次,找出数组中的某个元素
- 给定一棵二叉树,每个结点包含一个值。打印出所有满足以下条件的路径: 路径上结点的值加起来等于给定的一个值。注意:这些路径不必从根结点开始。