[各种面试题] 一个不能少:From陈利人先生微博面试题

题目描述:

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

你可能感兴趣的:([各种面试题] 一个不能少:From陈利人先生微博面试题)