给定n个数组编号1~n,给定一个范围,使得这个范围包含第k个数组至少ak个数的算法

这题给你许多个数组,让你给出一个范围,这个范围里面包含每个数组至少一个数,并且使这个范围尽可能的小。

包含第k个数组ak个数的算法解决方法和本题一模一样

使得这个范围里面包含每个数组至少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记录的是最后一个加以判定的组的左端,这个时候被记录的组就是最小的范围

  本题的思路还适用求一个集合,使得这个集合包含每个集合至少一个数,使得集合里面的数最少,或者是求一个范围,使得这个范围包含每个集合至少一个数,使得这个范围里面的数最少

这里的输入表示给定的n个二维数组,输出数组中有两个值,分别表示这个范围的start和end

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;
}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值