Arithmetic problem | 求出 N 座大楼的外轮廓线
2016-07-21 16:44
162 查看
这题目还是有一定难度,题目如下:
水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用三个数字表示
外轮廓线的表示方法为若干三元组,每个三元组包含三个数字 (start, end, height),代表这段轮廓的起始位置,终止位置和高度。
注意事项
请注意合并同样高度的相邻轮廓,不同的轮廓线在x轴上不能有重叠。
样例
给出三座大楼:
外轮廓线为:
解答时产生2个思路:(合理假设有利于解题)
【提前假设:1:全部大楼的start已按从小到大排序好,2:已知所有大楼中最大的end值为R,最小的start为L】
1:由于大楼三元组start,end都处于同一坐标轴上,因此可做相应的思维转换,“每点上方的高度可视为映射在坐标轴上的元素”,俗称”踩扁“,此后所有大楼轮廓(已处理)可视为一条有R+1长,映射着不同而又有连续性的元素的直线。只需要遍历每一座大楼,如果该大楼的高度比直线映射的元素要大,那么替换高度到相应的直线坐标轴上即可。后续处理该直线,让其成为轮廓三元组只需找到相应的连续元素即可完成。但当轮廓end在某一座大楼坐标中,该end点为轮廓的切割点,按实际来算该点映射有2个元素,但总显示相对高的元素而已。因此需要特别注意。
【优点:1:可忽略大楼的三元组顺序。2:无需判断任何可能性,因为直线上映射的元素替换是由比其高的元素决定的。3:可自动合并相邻同高度轮廓】
【缺点:虽然思维转换让问题本身显得相对容易,但其会影响一定的时间复杂度】
结构定义如下:
思路一代码实现如下:
2:两大楼的轮廓之间出现的行为可看为相交,包容,不相交3种。遍历每座大楼判断其与其他大楼之间的关系显然是一件吃力不讨好的事。但对于顺序处理的轮廓来说,却是另外一回事。
把每一座大楼的关系处理成轮廓与某大楼间的关系,是我这思路的重点。然而会得出结论如下:
1:顺序处理n座大楼,得到q个轮廓,第n+1座大楼与第q轮廓只会出现相交与不相交的情况。
2:第q轮廓start若出现于第n+1座大楼start后,则该大楼与第q,q-1轮廓面积上都有相交。因为产生该可能性轮廓的大楼关系为相交或包容。若否,则只可能与第q轮廓相交。
按照以上结论,只需把最后轮廓与目前处理的大楼按唯一的可能性进行处理动作就能完成解题。
【优点:时间复杂度相对较低】
【缺点:必须保证大楼start值已排序,但处理可能性比较费劲】
思路二代码实现如下:
水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用三个数字表示
(start, end, height),分别代表其在x轴上的起点,终点和高度。大楼之间从远处看可能会重叠,求出 N 座大楼的外轮廓线。
外轮廓线的表示方法为若干三元组,每个三元组包含三个数字 (start, end, height),代表这段轮廓的起始位置,终止位置和高度。
注意事项
请注意合并同样高度的相邻轮廓,不同的轮廓线在x轴上不能有重叠。
样例
给出三座大楼:
[ [1, 3, 3], [2, 4, 4], [5, 6, 1] ]
外轮廓线为:
[ [1, 2, 3], [2, 4, 4], [5, 6, 1] ]
解答时产生2个思路:(合理假设有利于解题)
【提前假设:1:全部大楼的start已按从小到大排序好,2:已知所有大楼中最大的end值为R,最小的start为L】
1:由于大楼三元组start,end都处于同一坐标轴上,因此可做相应的思维转换,“每点上方的高度可视为映射在坐标轴上的元素”,俗称”踩扁“,此后所有大楼轮廓(已处理)可视为一条有R+1长,映射着不同而又有连续性的元素的直线。只需要遍历每一座大楼,如果该大楼的高度比直线映射的元素要大,那么替换高度到相应的直线坐标轴上即可。后续处理该直线,让其成为轮廓三元组只需找到相应的连续元素即可完成。但当轮廓end在某一座大楼坐标中,该end点为轮廓的切割点,按实际来算该点映射有2个元素,但总显示相对高的元素而已。因此需要特别注意。
【优点:1:可忽略大楼的三元组顺序。2:无需判断任何可能性,因为直线上映射的元素替换是由比其高的元素决定的。3:可自动合并相邻同高度轮廓】
【缺点:虽然思维转换让问题本身显得相对容易,但其会影响一定的时间复杂度】
结构定义如下:
typedef struct mab { int start,end,hight; } mab;
思路一代码实现如下:
void Method_1(mab *p,int len,vector<mab>&v) { int i,f,r=0; mab q; for(i=0; i<len; ++i) { if(p[i].end>r) r=p[i].end; } char *t=new char[r+1]; memset(t,0,r+1); for(i=0; i<len; ++i) for(f=p[i].start; f<=p[i].end; ++f) if(t[f]<p[i].hight) t[f]=p[i].hight; for(f=0; f<r+1; ++f) { if(t[f]>0) { q.start=f; for(i=f; i<r+1; ++i) if(t[i]!=t[f]) break; f=i-1; for(i=0; i<len; ++i) if(p[i].start<f+1&&p[i].end>f+1) break; if(i!=len) q.end=f+1; else q.end=f; q.hight=t[f]; v.push_back(q); } } delete[] t; }
2:两大楼的轮廓之间出现的行为可看为相交,包容,不相交3种。遍历每座大楼判断其与其他大楼之间的关系显然是一件吃力不讨好的事。但对于顺序处理的轮廓来说,却是另外一回事。
把每一座大楼的关系处理成轮廓与某大楼间的关系,是我这思路的重点。然而会得出结论如下:
1:顺序处理n座大楼,得到q个轮廓,第n+1座大楼与第q轮廓只会出现相交与不相交的情况。
2:第q轮廓start若出现于第n+1座大楼start后,则该大楼与第q,q-1轮廓面积上都有相交。因为产生该可能性轮廓的大楼关系为相交或包容。若否,则只可能与第q轮廓相交。
按照以上结论,只需把最后轮廓与目前处理的大楼按唯一的可能性进行处理动作就能完成解题。
【优点:时间复杂度相对较低】
【缺点:必须保证大楼start值已排序,但处理可能性比较费劲】
思路二代码实现如下:
void Method_2(mab *p,int len,vector<mab>&t) { mab x,xx; t.push_back(p[0]); int i,l; for(i=1; i<len; ++i) { l=t.size()-1; xx=t[l]; if(p[i].start<xx.start){ x=t[t.size()-2]; if(p[i].end<xx.start){ if(p[i].hight>x.hight){ t[l-1].end=p[i].start; t[l]=p[i]; x.start=p[i].end; t.push_back(x); t.push_back(xx); } } else if(p[i].end>xx.end){ if(p[i].hight>xx.hight){ if(p[i].hight>x.hight){ t[l-1].end=p[i].start; t[l]=p[i]; } else if(p[i].hight==x.hight){ t[l-1].end=p[i].end; t.pop_back(); } else{ t[l].hight=p[i].hight; t[l].end=p[i].end; } } } else{ if(xx.hight==p[i].hight) t[l].end=p[i].end; else{ x=p[i]; x.start=xx.end; t.push_back(x); } } } else{ if(p[i].end>xx.end){ if(p[i].start>xx.end){ if(xx.end+1==p[i].start&&xx.hight==p[i].hight) t[l].end=p[i].end; else t.push_back(p[i]); } else{ if(p[i].hight>xx.hight){ t[l].end=p[i].start; t.push_back(p[i]); } else if(p[i].hight==xx.hight){ t[l].end=p[i].end; } else{ xx=p[i]; xx.start=t[l].end; t.push_back(xx); } } } else{ if(xx.hight<p[i].hight){ t[l].end=p[i].start; t.push_back(p[i]); xx.start=p[i].end; t.push_back(xx); } } } } }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法