leetcode.587.Erect the Fence

凸包问题。好像是我在leetcode做的第一个凸包问题吧。

第一次做,涉及到的东西还是蛮多的。有一个东西很重要,就是已知一个点和一个矢量,求这个点在这个矢量的左边还是右边。网上都是用一个点对于已知直线的位置的描述,用矢量代替直线更准确,直观。

http://blog.csdn.net/modiz/article/details/9928955一个是用面积法描述的

http://blog.csdn.net/modiz/article/details/9928553一个用矢量的叉积描述的

其实我看上去感觉都是一样的貌似的。。其实都是用矢量的叉积描述的。

定义:平面上的三点A(x1,y1),B(x2,y2),C(x3,y3)组成三角形的面积是:

S(A,B,C)=|y1 y2 y3|= [(x1-x3)*(y2-y3)-(y1-y3)*(x2-x3)]/2

这是用向量的混合积表示的面积,

就像这样。。绘图潦草。。 这个求出来的面积应该就是这样的,x轴为矢量AB的方向,所以可以理解为x轴上面的面积为S,下面的面积为-S,所以S为负数,点C就在矢量AB的右侧,S为正数,C就在矢量AB的左侧。这样理解不是很直观嘛。


然后我就写一下我的思路,也是从leetcode上的Sloution上借鉴的,Sloution也是来源于http://www.algorithmist.com/index.php/Monotone_Chain_Convex_Hull.cpp

思路:

1.把points按x轴上的坐标由小到大(有大到小也可以)进行排序,相等就按y轴

2.先放入两个点,

3.开始遍历points,每放入一个point         //为了构造凸包下面的边界

4.判断以栈顶两个元素组成的向量,判断这个点是否在向量的左侧或者线上,若是,则放入栈,若在右侧,出栈一个元素,重新执行步骤4;直到遍历完points

5.反向遍历points,执行步骤3                  //为了构造凸包上面的边界

6.去除栈中相同的points

构造下面边界时的情况,当发现下一个点是C并且在栈顶AB的右侧,此时B出栈,构造向量OA,这里不画了,可以发现C在OA的左侧,所以C进栈。

然后遍历到点D,构造向量AC,发现D就在AC的左侧,所以直接进栈。通过这种方式,一点一点确定边界范围。同理确定上面的边界的时候也是这个方式,自己手动画一下就很直观地明白了。

贴一下AC代码吧,注释相当详细

 /**
* Definition for a point.
* struct Point {
* int x;
* int y;
* Point() : x(0), y(0) {}
* Point(int a, int b) : x(a), y(b) {}
* };
*/
class Solution {
public:
typedef int coord_t;
//防止计算量太大
typedef long long coord2_t; //通过判断向量的点积正负来确定点位于矢量左侧还是右侧
coord2_t cross(const Point &O,const Point &A,const Point &B){
return (A.x-O.x)*(coord2_t)(B.y-O.y)-(A.y-O.y)*(coord2_t)(B.x-O.x);
} //按x轴坐标排序,相等时用y轴坐标排序
static bool cmp(Point &p1,Point &p2){
return p1.x<p2.x||(p1.x==p2.x&&p1.y<p2.y);
} //去除duplicate的辅助函数
static bool equ(Point &p1,Point &p2){
return p1.x==p2.x&&p1.y==p2.y;
} vector<Point> outerTrees(vector<Point>& points) {
int n=points.size(),k=;
//遍历两轮,所以size为2n
//因为要用栈的顶部两个元素,所以用vector比要方便一些
vector<Point> res(*n); //排序
sort(points.begin(),points.end(),cmp); //正向遍历
for(int i=;i<n;i++){
//若在矢量的右侧,出栈
while(k>=&&cross(res[k-],res[k-],points[i])<) k--;
res[k++]=points[i];
} //反向遍历
for(int i=n-,t=k+;i>=;i--){
//若在矢量的右侧,出栈
while(k>=t&&cross(res[k-],res[k-],points[i])<) k--;
res[k++]=points[i];
} //重新resize并排序
res.resize(k);
sort(res.begin(),res.end(),cmp);
//除去相同的元素,unique函数的方法是吧相同的元素都放到vector的尾部,并返回一个这些相同元素起始的iterator
res.erase(unique(res.begin(),res.end(),equ),res.end());
return res;
}
};

另外删除vector中的重复数据(unique),这个技巧也是我刚学的。

凸包有很多计算方法http://www.7zhang.com/index/cms/read/id/327304.html,这个博主讲了很多,我选了一个最好理解的写了。

因为最近在学python,所以特地用python实现了一遍

 # Definition for a point.
# class Point(object):
# def __init__(self, a=0, b=0):
# self.x = a
# self.y = b class Solution(object):
def outerTrees(self, points):
"""
:type points: List[Point]
:rtype: List[Point]
"""
def sign(p,q,r):
#cmp函数比较a,b大小,a<b return -1,a==b return 0,a>b return 1
return cmp((p.x-r.x)*(q.y-r.y),(p.y-r.y)*(q.x-r.x)) def drive(hull,r):
hull.append(r)
# *hull[-3:]表示尾部三个元素
while len(hull)>=3 and sign(*hull[-3:])<0:
hull.pop(-2);
return hull; #lambda表示临时写的一个函数
points.sort(key=lambda p:(p.x,p.y))
#reduce(f,list,可以作为计算的初始值)
lower=reduce(drive,points,[])
#points[::-1]表示反转list
upper=reduce(drive,points[::-1],[]);
return list(set(lower+upper))

很多python的东西还不熟悉。。顺便熟悉一下。。

leetcode 587. Erect the Fence 凸包的计算的更多相关文章

  1. 587. Erect the Fence(凸包算法)

    问题 给定一群树的坐标点,画个围栏把所有树围起来(凸包). 至少有一棵树,输入和输出没有顺序. Input: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]] Output: ...

  2. 587. Erect the Fence

    Problem statement: There are some trees, where each tree is represented by (x,y) coordinate in a two ...

  3. [LeetCode] Erect the Fence 竖立栅栏

    There are some trees, where each tree is represented by (x,y) coordinate in a two-dimensional garden ...

  4. [LeetCode] Count of Smaller Numbers After Self 计算后面较小数字的个数

    You are given an integer array nums and you have to return a new counts array. The counts array has ...

  5. [Swift]LeetCode587. 安装栅栏 | Erect the Fence

    There are some trees, where each tree is represented by (x,y) coordinate in a two-dimensional garden ...

  6. TZOJ 2569 Wooden Fence(凸包求周长)

    描述 Did you ever wonder what happens to your money when you deposit them to a bank account? All banks ...

  7. Leetcode 587.安装栅栏

    安装栅栏 在一个二维的花园中,有一些用 (x, y) 坐标表示的树.由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树.只有当所有的树都被绳子包围时,花园才能围好栅栏.你需要找到正好位于栅栏边 ...

  8. Geometry-587. Erect the Fence

    There are some trees, where each tree is represented by (x,y) coordinate in a two-dimensional garden ...

  9. LightOJ 1239 - Convex Fence 凸包周长

    LINK 题意:类似POJ的宫殿围墙那道,只不过这道题数据稍微强了一点,有共线的情况 思路:求凸包周长加一个圆周长 /** @Date : 2017-07-20 15:46:44 * @FileNam ...

随机推荐

  1. 关于servlet中重定向、转发的地址问题

    先写一个正斜杠"/",再判断是服务器使用该地址还是网站使用该地址. 访问网络资源用/,访问硬盘资源用\. 例如: 转发:      request.getRequestDispat ...

  2. 设置网卡IP,还每次都挨个地址输入吗?批处理一下【转】

    1.设置网卡ip,子网掩码和默认网关,注意修改网卡名称,跟本地连接汇总的网卡名称保持一直 netsh interface ip set address "以太网" static 1 ...

  3. oracle 一个网站

    http://www.oracle.com/technetwork/cn/articles/11g-pivot-101924-zhs.html

  4. MVC公开课 – 2.查询,删除 (2013-3-15广州传智MVC公开课)

    查询 /Controller/HomeController.cs /// <summary> /// 查询 文章 列表 /// </summary> /// <retur ...

  5. Docker Zero Deployment and Secrets (一)

    在本节中,主要介绍在Docker swarm中如何不中断应用高可靠性的情况下更新服务和stack.这也叫做zero downtime deployment.还有就是swam如何管理密钥,保证容器之间的 ...

  6. HTML5 canvas绘制arcTo、translate和rotate的画法探索

      arcTo(x1,y1,x2,y2,radius) ; 还要加上moveTo的点(x0,y0) ; 第一步:找到切点 过点 (x1,y1), (x0,y0)引射线与点(x1,y1),(x2,y2) ...

  7. IntelliJ IDEA 编译程序出现 非法字符 的 解决方法(转)

    百度到很多方法,比如(删了文件重新建:先改成GBK再UTF8:粘贴到notpad++上改utf8),但都没有解决问题.下面这种方法确实有效,先记下来,如果有其他好方法将来在补充…… 文章来源:  ht ...

  8. Anaconda 安装 pydot 绘制树状图

    在***的前提下,控制台输入以下命令: 首先安装 graphviz,这是计算的核心 package conda install graphviz 再安装 pydot ,这是 graphviz 的 py ...

  9. 哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)I - 没有名字

    题目描述 tabris实在是太菜了,没打败恶龙,在绿岛也只捡到一块生铁回去了,为了不在继续拉低acimo星球的平均水平逃离地球,来到了Sabi星球. 在这里tabris发现了一种神奇的生物,这种生物不 ...

  10. python笔记六:进程与线程

    1.进程 1)调用unix/linux系统中的进程函数fork(),用法和linux相同,调用成功返回0,失败返回-1: import os print 'Process (%s) start...' ...