题目描述:
一个不能少:有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; }