算法编程题-如何判断一个点是否在三角形内

原题描述

最近在刷codetop上的腾讯算法题时,有一道题目就是判断一个点是否在三角形内,给定这个三角形的三个顶点的坐标和要判断的这个点的坐标。

思路方法

等面积法

思路

很容易想到的是,可以用等面积法。如下图,O点如果在三角形内的话,显然O与三角形任意两边所形成的三角形的面积之和等于大三角形ABC的面积之和,但如果点O在三角形外的话,这样的等式显然是不成立的。
图一
利用这个性质可以判断点是否在三角形内,但严谨一点,点如果在边上也是满足这个等式的,所以在分别求取小三角形面积的时候,可以判断一下面积是否为零,为零则说明点在边上。根据三角形的三个顶点求取三角形面积可以使用海伦公式,假设a,b,c分别为三角形的三边长。计算公式如下。
p = a + b + c 2 p=\frac{a+b+c}{2} p=2a+b+c
S = p ∗ ( p − a ) ∗ ( p − b ) ∗ ( p − c ) S=\sqrt{p * (p-a) * (p-b) * (p-c)} S=p(pa)(pb)(pc)
但是等面积法在程序实现上由于计算机处理浮点数的误差,在比较的时候不能判断两个面积是否相等,而是应该判断两个差的绝对值是否在一个很小的数范围内。但是牛客网的测试数据中,依然有部分数据无法正常通过。

代码

type Point struct {
   
   
	X, Y float64
}


// 给定三角形的三个顶点,求取三角形面积
func getTriangleArea(triangle [3]Point) float64 {
   
   
	edges := make([]float64, 3)
	for i := 0; i < 3; i++ {
   
   
		x1, y1 := triangle[i].X, triangle[i].Y
		x2, y2 := triangle[(i + 1) % 3].X, triangle[(i + 1) % 3].Y
		edges[i] = math.Sqrt(float64((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)))
	}
	p := (edges[0] + edges[1] + edges[2]) / 2
	return math.Sqrt(p * (p - edges[0]) * (p - edges[1]) * (p - edges[2]))
}


func isPointInTri(triangle [3]Point, point Point) bool {
   
   
	// 面积法
	totalArea := getTriangleArea(triangle)
	area := 0.0
	for i := 0; i < 3; i++ {
   
   
		tri := triangle   // 数组的话,这里会拷贝一份,与切片不同
		tri[i] = point
		area1 := getTriangleArea(tri)
		if area1 < 1e-5 {
   
      // 点可能在边上
			return false 
		}
		area += area1
	}
	return math.Abs(totalArea - area) < 1e-5   // 浮点数的比较
}

复杂度分析

  • 时间复杂度: O ( 1 ) O(1) O(1)
  • 空间复杂度: O ( 1 ) O(1) O(1)

叉乘法

思路

注意观察上图,可以发现,如果点在三角形内,那么对于任意一条边来说,该点和三角形剩下的一个点一定出现在这条边的同一侧,如果点不在三角形内,那么一定存在一条边,使得三角形外的该点和三角形剩下的一个点出现在这条边的两侧。利用这个性质,也可以判断点是否在三角形内。
那么如何判断两个点是否在一条边的同一侧呢?这里可以利用叉乘的性质。如下图,对于边OB来说,点A和点C是否在同一侧,可以利用以下的式子的正负号来判断,如果为正,则在同一侧,否则不在同一侧。

在这里插入图片描述
R = ( O A ⃗ × O B ⃗ ) ∗ ( O C ⃗ × O B ⃗ ) R=(\vec{OA} \times \vec{OB}) * (\vec{OC} \times \vec{OB})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值