程式設計之美之高效安排見面會

fangjian1204發表於2014-08-14

對於原題,書上寫的很詳細,即圖的著色問題,這裡主要看第一個擴充套件和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;
    }
};


相關文章