持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
每日刷题 2022.06.08
- leetcode原题链接:leetcode.cn/problems/va…
- 难度:简单
- 方法:斜率
题目
- 给定一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点,如果这些点构成一个 回旋镖 则返回 true 。
- 回旋镖 定义为一组三个点,这些点 各不相同 且 不在一条直线上 。
示例
- 示例1
输入: points = [[1,1],[2,3],[3,2]]
输出: true
- 示例2
输入: points = [[1,1],[2,2],[3,3]]
输出: false
提示
points.length == 3points[i].length == 20 <= xi, yi <= 100
相似题目
- 2280. 表示一个折线图的最少线段数
- 这个题目的坑点:1.对于所有的节点需要进行排序,因为节点无序的话,就不能判断是否是连续的,可能会额外的计算线段数。2.求斜率的时候,存在精度的问题,因为数值比较大,精度会存在丢失的情况,那么就会导致两个斜率不同的判断成相同的。
解题思路
解决方法1
- 可以将其转换成三点一线的做法,判断相邻的三个点是否在一条直线上,如果在一条直线上,就不需要新增线段数;反之就需要新增额外的线段数。(使用向量叉积的做法)
解决方法2
- 如果乘积得到的数据也很大的话,会超出的,那么就可以使用
GCD的做法。计算斜率时以元组的形式保留分子和分母的最简式。通过分别计算上一次以及这一次的x和y的最大公约数GCD,将x和y化为最简式后,进行比较是否相等即可,这样就可以避免精度的问题。
var minimumLines = function(stockPrices) {
let s = stockPrices, n = s.length, sum = 0;
if(n == 1) return sum;
function gcd(x, y) {
return y == 0 ? x : gcd(y, x % y);;
}
s.sort((a, b) => a[0] - b[0]);
sum++;
for(let i = 1; i < n - 1; i++) {
let x = s[i][0] - s[i - 1][0], y = s[i][1] - s[i - 1][1];
// 计算上一个x和y的最大公约数
let k = gcd(x, y);
x /= k, y /= k;
let x1 = s[i + 1][0] - s[i][0], y1 = s[i + 1][1] - s[i][1];
// 计算当前的x和y差值的最大公约数
let k1 = gcd(x1, y1);
x1 /= k1, y1 /= k1;
// 比较两个化简后的分子、分母是否相等
if(x == x1 && y == y1) continue;
// 只有斜率不相等的时候,才需要++
else sum++;
}
return sum;
};
本题的解题思路
- 分析:需要三个点个不相同,并且不在一条直线上
- 因此可以得到两个要求:各不相同、不在一条直线上
- 既然是要求线段数,那么我们思考下,一共有
n个数,那么就有n - 1个线段。
斜率做法
- 计算两个点之间的线段的斜率,比较这次的斜率和上次的是否一致
- 注意⚠️,除法的精度丢失和乘法的数据超出,必要的时候可以使用
GCD来解决。
假设坐标:a(x1, y1) ,b(x2, y2) ,c(x3, y3)
(y1 - y2) / (x1 - x2) = (y2 - y3) / (x2 - x3) = k
转换成乘法:(y1 - y2) * (x2 - x3) = (x1 - x2) * (y2 - y3)
- 最开始的时候,记上一轮的
preX = 0, preY = 1, k = 1 / 0,因为对于每一个节点来说,其比较的过程中记录的是其相连的后面的那条边,那么对于第一个点来说,必须要res++(线段数+1)
向量做法
- 因为有三个点,
a,b,c - 几何原理:证明三点不共线,只需要从同一点出发到两个不同点的斜率不同即可。
- 如果三个点共线的话,则向量
ab与ac是平行的,因此(向量叉乘做法):假设坐标:a(x1, y1) ,b(x2, y2) ,c(x3, y3) 向量ab = ((x2 - x1), (y2 - y1)) 向量ac = ((x3 - x1), (y3 - y1)) 如果两直线平行,则: (y2 - y1) / (x2 - x1) = (y3 - y1) / (x3 - x1) 因为除法会出现0的问题和精度问题, 因此转换成乘法计算, 即:(y2 - y1) * (x3 - x1) = (y3 - y1) * (x2 - x1) - 因为向量做法,最终会停留在
i = n - 2的位置上,跳出循环,那么此时还存在一条边没有判断。假设跳出的时候,三点是在一条直线上的,那么最后的这条边需要记录;反之,如果跳出的时候,三点不是在一条直线上的,那么最后这个是需要记录的 - 因此不论三点在不在一条线上最后线段都需要+1,也可以反向思维,初始化线段数为
n - 1,这样只需要碰到在一条直线上的减去一个线段数即可。
面积做法
- 三点如果共线的话,那么组成的三角形面积为
0;反之,面积不为0 - 已知三个点的坐标,求解三角形的面积公式如下:需要牢记)
S = 1 / 2 * [(x1y2 - x2y1)+ (x2y3 - x3y2) + (x3y1 - x1y3)]
AC代码
/**
* @param {number[][]} points
* @return {boolean}
*/
var isBoomerang = function(points) {
// 计算三个点之间的斜率
const p = points;
return (p[1][1] - p[0][1]) * (p[2][0] - p[1][0]) != (p[2][1] - p[1][1]) * (p[1][0] - p[0][0]);
};