编程之美之高效安排见面会

对于原题,书上写的很详细,即图的着色问题,这里主要看第一个扩展和leetcode上相关的问题

扩展问题一:

简单的说就是:有 N 个面试要同时进行, 他们的面试时间分别是 B[i], E[i]. 我们希望将这N个面试安排在若干地点, 不同的面试在同一时间不能再相同的面试点. 问至少需要多少个面试点

思路:先按照开始时间排序,对每个节点赋颜色值时,在它之前开始并且有时间重叠的区域的颜色不能使用

struct Interval {
     int start;
     int end;
	 int color;
     Interval() : start(0), end(0),color(-1) {}
     Interval(int s, int e,int c) : start(s), end(e) ,color(c) {}
};

bool operator<(const Interval& lhs,const Interval& rhs)
{
	return (lhs.start < rhs.start || (lhs.start == rhs.start && lhs.end < rhs.end));
}

bool isOverLap(const Interval& lhs,const Interval& rhs)
{
	if(lhs.start >= rhs.start && lhs.start < rhs.end)return true;
	if(rhs.start >= lhs.start && rhs.start < lhs.end)return true;
	return false;
}
int interviewPoint(vector<Interval>& intervals)
{
	sort(intervals.begin(),intervals.end());//按开始时间排序
	int length = intervals.size();
	vector<bool>isForbidden(length+1,false);
	int i,j,maxColor = 1;
	for(i = 0; i < length;++i)
	{
		for(j = 0;j < i;++j)
		{
			if(isOverLap(intervals[i],intervals[j]))isForbidden[intervals[j].color] = true;//如果区域重叠,则它的颜色不能使用
		}
		for(j = 1;j <= maxColor;++j)
		{
			if(isForbidden[j] == false)break;
		}
		if(j > maxColor)intervals[i].color = ++maxColor;
		else intervals[i].color = j;
		isForbidden.assign(length+1,false);
	}
	return maxColor;
}

编程之美上说,如果只需要求出面试点的个数,则可以对所有开始结束时间进行排序,然后遍历,这里有一点没有说清楚,就是当结束时间和开始时间相同时,要把所有的结束时间放在前面,具体如下:

struct Interval {
     int start;
     int end;
     Interval() : start(0), end(0) {}
     Interval(int s, int e,int c) : start(s), end(e){}
};
struct Time //用于排序
{
	int time;
	bool isStart;//标记
	Time(int t,bool s):time(t),isStart(s){}
};
bool operator<(const Time& lhs,const Time& rhs)
{
	return (lhs.time < rhs.time || lhs.time == rhs.time && !lhs.isStart); //时间相同时,结束时间在前
}

int interviewPoint(vector<Interval>& intervals)
{
	vector<Time> data;
	int i,maxColor = 0,count = 0;
	for(i = 0;i < intervals.size();++i)
	{
		data.push_back(Time(intervals[i].start,true));
		data.push_back(Time(intervals[i].end,false));
	}
	sort(data.begin(),data.end());

	for(i = 0; i < data.size();++i)  //遇到开始时间,加1,遇到结束时间,减1
	{
		if(data[i].isStart)
		{
			if(++count > maxColor)maxColor = count;
		}
		else --count;
	}
	return maxColor;
}

leetcode上两个和时间段相关的问题

Merge Intervals

 

Given a collection of intervals, merge all overlapping intervals.

For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

思路:这个题目比较简单,就是先按照开始时间排序,然后遍历整个数组,用两个指针指向相邻的两个位置,如果需要合并,就合并,不需要合并就得到一个结果。

struct Interval {
     int start;
     int end;
     Interval() : start(0), end(0) {}
     Interval(int s, int e) : start(s), end(e) {}
};

bool operator<(const Interval& lhs,const Interval& rhs)
{
	return (lhs.start < rhs.start || (lhs.start == rhs.start && lhs.end < rhs.end));
}

class Solution {
public:
    vector<Interval> merge(vector<Interval>& intervals) {
    	sort(intervals.begin(),intervals.end());//按照开始时间排序
    	vector<Interval> res;
    	vector<Interval>::iterator iter = intervals.begin();
    	Interval* cur = NULL;
    	for(;iter != intervals.end();++iter)//进行时间段的合并
    	{
    		if(cur != NULL)
    		{
    			if(cur -> end >= iter -> start)
    			{
    				cur -> end = (cur -> end > iter -> end) ? cur -> end : iter -> end;//这里改变了原来的数据,面试的时候要具体对待
    			}
    			else 
    			{
    				res.push_back(*cur);
    				cur = &(*iter);
    			}
    		}
    		else cur = &(*iter);
    	}
    	if(cur)res.push_back(*cur);
    	return res;
    }
};

Insert Interval

 

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

You may assume that the intervals were initially sorted according to their start times.

Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].

Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].

This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

思路:把原链表分成三段,首尾是不需要进行合并的,中间是需要进行合并的,为了加快速度,可以用二分查找定位到第一个需要合并的节点的位置。

class Solution {
public:
    int binarySearch(vector<Interval> &intervals,Interval newInterval)//定位到第一个需要合并的节点的位置
    {
    	int left = 0,right = intervals.size() - 1;
    	while(left <= right)
    	{
    		int mid = left + ((right - left) >> 1);
    		if(intervals[mid].end < newInterval.start)left = mid + 1;
    		else right = mid - 1;
    	}
    	return left;
    }
    vector<Interval> insert(vector<Interval> &intervals, Interval newInterval) {
    	if(intervals.size() == 0)return vector<Interval>(1,newInterval);
    	vector<Interval> res;
    	int pos = binarySearch(intervals,newInterval);
    	int i;
    	for(i = 0; i < pos;++i)res.push_back(intervals[i]);//地一段
    	for(;i < intervals.size();++i)//第二段
    	{
    		if(intervals[i].start >= newInterval.start && intervals[i].start <= newInterval.end || newInterval.start >= intervals[i].start  && newInterval.start <= intervals[i].end)
    		{
    			newInterval.start = min(newInterval.start,intervals[i].start);
    			newInterval.end = max(newInterval.end,intervals[i].end);
    		}
    		else break;
    	}
    	res.push_back(newInterval);
    	for(;i < intervals.size();++i) res.push_back(intervals[i]);//第三段
    	return res;
    }
};

    原文作者:fangjian1204
    原文地址: https://blog.csdn.net/fangjian1204/article/details/38558027
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞