前言
验证所有点在一条直线上,只需确定y=kx + b的k与b即可,但是k可能是无穷大,即直线垂直的时候。将函数抽象为x=0*y + b,这样还不够抽象,将x/y都视为一个变量时,两种情况对调传递变量即可统一操作。
一、案例
二、题解
step1. 通过两点确定抽象函数的k 与 b
step2.分情况传递对调参数,如何对调?可以通过给出起点start+step为正一负一控制。
class Solution {
// 两个点确定一条直线。
// 先确定直线,再验证其他点。
// 直线看斜率,斜率分两种,[0,+∞) & x = b
// x/y都是变量,统一成函数即可。
public boolean checkStraightLine(int[][] coordinates) {
int x1 = coordinates[0][0],y1 = coordinates[0][1];
int x2 = coordinates[1][0],y2 = coordinates[1][1];
// 情况1:无穷斜率
if(x1 == x2) return isStraightLine(coordinates,0,x1,1,-1);
// 情况2:y = kx + b
double k = (y2 - y1) * 1.0 / (x2 - x1);
return isStraightLine(coordinates,k,y1 - k * x1,0,1);
}
// 巧设变量值,将无穷斜率和正常斜率操作统一起来。
public boolean isStraightLine(int[][] coordinates,double k,double b,int start,int step){
for(int[] c : coordinates){
if(c[start] * k + b != c[start + step]) return false;
}
return true;
}
}
// y = kx + b || x = c
// 两点确定k&b,将上面两个函数抽象成:变量1 = k * 变量2 + b,用一个函数统一处理。
func checkStraightLine(coordinates [][]int) bool {
// 给出两点
x1,y1 := coordinates[0][0],coordinates[0][1]
x2,y2 := coordinates[1][0],coordinates[1][1]
// 情况1:x = 0 * y + b
if x1 == x2 {
return isStraightLine(coordinates,0,float64(x1),1,-1) // start = 1;step = -1来控制x/y的取值
}
// 情况2:y = k * x + b
k := float64(y2 - y1) / float64(x2 - x1)
return isStraightLine(coordinates,k,float64(y1) - k*float64(x1),0,1)
}
// 巧用变量start|step来抽象统一所有斜率的操作
func isStraightLine(coordinates [][]int,k,b float64,start,step int) bool {
for _,c := range coordinates {
// 验证y = kx + b
if float64(c[start]) * k + b != float64(c[start + step]) {
return false
}
}
return true
}
总结
1)通过抽象问题,将问题视为一个模型,采用函数处理,做到复用简洁。
2)积累一些巧妙的方法,比如step为正一负一来控制走向,start来控制起点;除此之外,像idx++ & 1这种不断在0-1之间循环也比较常用。
参考文献
[1] LeetCode 缀点成线