题目描述:
一个不能少:有k个有序的数组,请找到一个最小的数字范围。使得这k个有序数组中,每个数组都至少有一个数字在该范围中。例如:
数组1: 4, 10, 15, 24, 26;
数组2: 0, 9, 12, 20;
数组3: 5, 18, 22, 30。
所得最小范围为[20,24],其中,20在2中,22在3中,24在1中。请关注微信公众账号“待字闺中”。
如果在LeetCode上做过Minimum Window Substring一题的话那这题应该不算太难,只是稍微转了个弯而已。
因为呆会还有事,所以这里只简单描述我的思路,并赋以完整代码:
(注意下面我只是针对例子,写的是3个数组的情况,扩展到K个数组只需要改几行而已,相信聪明的您自己也能解决的~
同样,我们还可以扩展成: 求一个最小范围,包含k1个数组1的元素,k2个数组2的元素,k3个数组3的元素,等等。这样的扩展也是很容易修改的)
1.首先我们归并所有的数组,记为sortedArray,这个数组中每个元素要包含两个信息,一是来自哪个数组from,一是代表的数字,所以经过此次步骤我们得到:
sortedArray:
from: 2,1,3,2, 1, 2, 1, 3, 2, 3, 1, 1 ,3,
number: 0,4,5,9,10,12,15,18,20,22,24,26,30
2.然后我们利用Minimum Window Substring的思想来解决这个问题,我们想象一个滑动的窗口 [ start, end ], 它必须满足一个条件,就是每个数组中都有元素在这个窗口中,然后我们也很容易得到这个窗口所包含的Range范围,即是 sortedArray[ end] .number - sortedArray[start].number ,如果这个Range范围比之前保留的范围更小,则更新一下即可。
3.而这个窗口的滑动策略是这样的: 把end代表的这个元素加进来,并累加已包含的该数组元素数量,然后检查是否3个数组都有元素了,现在我们滑动左范围start,检查start位置的元素是否是冗余的,如果是则可以除去,然后按上面说的来更新最小范围。
代码附在下面,直接可以执行,您有兴趣可以拷贝到您的环境中跑一下!
如果有错误,恳请您提出来,也帮助我进步! : )
#include<iostream>
#include<vector>
using namespace std;
struct node
{
int from,number;
node(int f,int n):from(f),number(n){}
};
vector<int> array1,array2,array3;
vector<node> sortedArray;
void input(vector<int>& array)
{
int n,t; //size of array
cin>> n;
array.reserve(n);
for(int i=0;i<n;i++)
{
cin>>t;
array.push_back(t);
}
}
void init()
{
input(array1);
input(array2);
input(array3);
}
int min3(int x,int y,int z)
{
return min(x,min(y,z));
}
void merge()
{
const int GUARD=10000000;
array1.push_back(GUARD);
array2.push_back(GUARD);
array3.push_back(GUARD);
int p1,p2,p3;
p1=p2=p3=0;
while(1)
{
int tmp=min3(array1[p1],array2[p2],array3[p3]);
if (tmp==GUARD)
break;
else
{
int from;
if (array1[p1]==tmp )
p1++,from=1;
else if (array2[p2]==tmp)
p2++,from=2;
else
p3++,from=3;
sortedArray.push_back(node(from,tmp));
}
}
array1.pop_back();
array2.pop_back();
array3.pop_back();
}
pair<int,int> getMinRange()
{
merge();
vector<int> need(4,1);
vector<int> have(4,0);
int needCnt=3;
const int MAX_DIFF=100000000;
int lRange=-1,rRange=-1;
int minDiff=MAX_DIFF;
int start=0;
int size=sortedArray.size();
for( int end=0;end<size;end++)
{
int from=sortedArray[end].from;
int num=sortedArray[end].number;
have[from]++;
if ( have[from] <=1 ) //one is enough
needCnt--;
if ( needCnt==0 )
{
while(1)
{
int tFrom=sortedArray[start].from;
if (have[tFrom]>1)
have[tFrom]--;
else
break;
start++;
}
int right=sortedArray[end].number;
int left=sortedArray[start].number;
if ( right-left <= minDiff )
{
minDiff=right-left;
lRange=left;
rRange=right;
}
}
}
return pair<int,int>(lRange,rRange);
}
int main()
{
init();
pair<int,int> ans = getMinRange();
cout<< "The Minimum Range is : [ "<<ans.first <<" , "<<ans.second<<" ] "<<endl;
}