Arithmetic problem | 求出 N 座大楼的外轮廓线

这题目还是有一定难度,题目如下:


水平面上有 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);
                }
            }
        }
    }
}

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值