MergeIntervals

本文详细阐述了如何通过优化排序策略和利用链表特性,解决合并区间问题,显著提高了算法的执行效率。从原始的排序方法到采用链表进行高效插入和删除操作,作者分享了其在不同测试样例中遇到的问题和解决方案,最终通过链表实现了问题的有效解决。文章还探讨了操作次数和时间复杂度的优化,以及如何在实际应用中选择最合适的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拿到题目,一看,对于两个interval分类讨论,一共三种情况,部分包含,全部包含,不包含,然后写个逻辑区分这三种情况

显然需要先排序,排序的目的是当前的和后面一个合并,不需要再考虑前面的interval.  但是是start 还是end呢?最大兼容活动子集问题用的是end排序,这里我也优先考虑这个,但是发现会出问题,例如[1,3] [4, 6] [2,9] 这样的话12区间不并,23并但是还要和1并这就不行了,因此尝试start


进行简短的证明:

按照start 排序, [satrt1,end1]  satrt2,end2]  satrt3,end3] 可以得到start2<start3,由于end1<start2 因此end1< start3, 主要是 2 3 merge之后[start2,end3] 一定与1 不能merge 

按照end 排序  [satrt1,end1]  satrt2,end2]  satrt3,end3]  可以得到end1<sart2<end2<end3, 然而2,3合并结果可能是[start3,end3] 可能出现start3<end1的情况,因此不能保证与1不merge。

因此选择start排序,可以从前到后i遍历,不考虑 i-1是否需要merge


判断逻辑其实分3种:

1. s1.begin  s2.begin  s1.end, s2.end 或者switch s1 s2

2 s1.begin s2,begin s2.end s1.end 或者switch s1 s2

3. s1.begin s1.end s2.begin s2.end 或者switch s1 s2


然后里面出现merge,删除两个,插入并好的一个优点纠结,一开始以为start倒序 可以 全用push_back pop_back 但是 后面发现还是不行,因为后面还是有中间的删除,于是暂时用 vector 中间删,中间差来实现, insert erase 参数要用iterator


附上代码,还没过,编译不过,不认识带compare的sort函数= =我用gcc 3.2.3和 4.5.4都过了,gcc 4.7.3 居然和我说不过编译。。。。(问题出在SortComp要是static,leetcode系统维护人员这么做,好吧,问题都出在我这里,我忘记测试环境是面向对象的代码,于是乎class内部的函数写成静态表示不属于某个对象,而是属于这个class的 )

bool SortComp(const Interval& T1, const Interval&T2)
{
	return T1.start<T2.start;
}
bool ShouldMerge(Interval& n1,Interval& n2, Interval& mergedn)
{
	if(n1.start<=n2.start&&n2.start<=n1.end&&n1.end<=n2.end)//intersect
	{
		mergedn.start=n1.start;
		mergedn.end=n2.end;
		return true;
	}
	if(n1.start<=n2.start&&n2.end<=n1.end)//subset of another
	{
		mergedn.start=n1.start;
		mergedn.end=n1.end;
		return true;
	}
	return false;
}
vector<Interval> merge(vector<Interval> &intervals)
{
	sort(intervals.begin(),intervals.end(),SortComp);//start sort ascending

	for(int i=0;i<intervals.size()-1;i++)
	{
		Interval mergedn;
		if(ShouldMerge(intervals.at(i),intervals.at(i+1),mergedn)|| ShouldMerge(intervals.at(i+1),intervals.at(i),mergedn))
		{
			intervals.erase(intervals.begin()+i);
			intervals.erase(intervals.begin()+i);
			intervals.insert(intervals.begin()+i,mergedn);
			i--;
		}
		else 
			;
	}
	return intervals;
}

PS:这是一道4* 的题目,应该有一番斗争了,担心时间效率不过。事实确实这么做vector大量移动元素,超时了,

Last executed input: [[74,78],[61,63],[46,50],[51,54],[50,50],[60,64],[39,42],[25,27],[91,95],[14,16],[85,85],[5,7],[45,46],[45,49],[66,66],[73,73],[25,26],[25,26],[45,48],[67,67],[63,65],[82,84],[90,92],[47,49],[3,4],[1,5],[64,66],[73,77],[90,94],[20,21],[84,87],[48,49],[80,80],[85,85],[53,55],[21,23],[31,34],[71,75],[62,65],[8,9],[32,33],[7,8],[20,22],[57,57],[51,53],[18,21],[71,75],[49,50],[44,45],[28,31],[38,42],[15,17],[4,7],[48,52],[9,10],[37,38],[69,70],[89,89],[28,29],[52,52],[75,76],[20,21],[90,94],[49,53],[56,59],[84,85],[79,83],[20,21],[90,93],[55,59]
OJ后台有各种变态的测试样例,我小脆弱的C++程序啊,你要经受住时间复杂度的考验啊~~~~~~


昨天发现自己操作vector merge时犯了严重错误,几乎时操作次数double,本来合并两个,不需要删除两个元素,再插入合并的元素,只需删除第一个,然后替换第二个就可以了。出现这一问题,主要是一开始没有把整个大的逻辑框图设计好,而过早设计细节,就和读论文一样,先看大标题,摘要,结论,有个bird view, 然后再细节,设计复杂程序尤其如此,先写大的框架,不要先把实现细节写完,否则后面的大框架都没想清楚,所以但是细节是否能实现做到心中有数。所以前面写的不拘泥于细节的伪代码很有用的

小优化后,还是超时了,操作次数最多 n-1 +n-2....+1 =O(n^2) 可见需要更优的

想到一个刮三的算法,先copy到linklist,利用它的高效插入删除,然后再copy回vector, 时复O(n) 空复O(n) 可以尝试下

果然就过了,这次写linklist比较顺手一些,因为以前写经常会某些case指针就挂掉了,所以每次访问next都想清楚就OK了,看来链表在多次插入删除时效率极高,而且他还容忍我新建一个struct~~~

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
struct Node
{  
    Interval interval;
	Node* next;
};
class Solution {
public:

static bool SortComp(const Interval& T1, const Interval&T2)
{
	return T1.start<T2.start;
}
Node* CreateLinkList(vector<Interval> data)  
{  
    Node* head=NULL;  
    head=new Node();  
    head->interval=data[0];  
    head->next=NULL;  
    Node* rail=head,*p;// record each rail  
    for(int i=1;i<data.size();i++)  
    {  
        p=new Node();  
        p->interval=data[i];  
        p->next=NULL;  
        rail->next=p;  
        rail=rail->next;  
    }  
    return head;  
}
bool ShouldMerge(Interval n1,Interval n2, Interval& mergedn)
{
	if(n1.start<=n2.start&&n2.start<=n1.end&&n1.end<=n2.end)//intersect
	{
		mergedn.start=n1.start;
		mergedn.end=n2.end;
		return true;
	}
	if(n1.start<=n2.start&&n2.end<=n1.end)//subset of another
	{
		mergedn.start=n1.start;
		mergedn.end=n1.end;
		return true;
	}
	return false;
}
vector<Interval> merge(vector<Interval> &intervals)
{
	if(intervals.size()<=1) return intervals;
	sort(intervals.begin(),intervals.end(),SortComp);//start sort descending, for vector pop_back
	Node* head=CreateLinkList(intervals);

	//merge interval with linklist
	Node* p=head;
	while(p->next!=NULL)//at least two node initially
	{
		Interval mergedn;
		if(  ShouldMerge(p->interval,p->next->interval,mergedn) ||    ShouldMerge(p->next->interval,p->interval,mergedn)   )
		{
			//delete p, p->next;
			//insert mergedn;
			p->interval=mergedn;
			p->next=p->next->next;
		}
		else
			p=p->next;
	}


	/*
	for(int i=0;i<intervals.size()-1;i++)
	{
		Interval mergedn;
		if(ShouldMerge(intervals.at(i),intervals.at(i+1),mergedn)|| ShouldMerge(intervals.at(i+1),intervals.at(i),mergedn))
		{
			intervals.erase(intervals.begin()+i);
			intervals.at(i)=mergedn;
			//intervals.erase(intervals.begin()+i);
			//intervals.insert(intervals.begin()+i,mergedn);
			i--;
		}
		else 
			;
	}*/

	//copy linklist to vector
	p=head;
	intervals.clear();
	while(p!=NULL)
	{
		intervals.push_back(p->interval);
		p=p->next;
	}

	return intervals;
}


};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值