题目地址:
https://leetcode.com/problems/check-if-it-is-a-straight-line/
给定平面坐标系 n n n个点的数组 A A A,即 A [ i ] A[i] A[i]代表平面中的点,问它们是否能确定一条直线。
可以以 A [ 0 ] A[0] A[0]为原点,看别的点与 A [ 0 ] A[0] A[0]之间直线的斜率。我们以一个数对 ( n , m ) (n,m) (n,m)表示斜率(真正的斜率实际上是 n m \frac{n}{m} mn),对斜率进行标准化,如果 m = 0 m=0 m=0那么令 n = + ∞ n=+\infty n=+∞,否则的话要求 m m m和 n n n互素并且 n n n非负(如果 n = 0 n=0 n=0则要求 m m m非负),具体做法是将它们除以最大公约数,然后保证 n n n非负。具体算法里,我们需要先找到第一个与 A [ 0 ] A[0] A[0]不同的点,这样才能确定直线的斜率 k k k,接下来再遇到别的点的时候只需要判断那个点与 A [ 0 ] A[0] A[0]的斜率也等于 k k k即可。代码如下:
import java.util.Arrays;
import java.util.Objects;
public class Solution {
class Slope {
// n / m
int n, m;
public Slope(int x, int y) {
// 斜率是无穷大,标准化之后n是正无穷,m是0
if (y == 0) {
n = Integer.MAX_VALUE;
return;
}
n = x;
m = y;
// 否则先让n和m互素
int gcd = gcd(n, m);
n /= gcd;
m /= gcd;
// 如果n是0,则让m非负;如果n是负,则让n变为正
if (n == 0) {
m = Math.abs(m);
} else if (n < 0) {
n = -n;
m = -m;
}
}
private int gcd(int x, int y) {
if (y == 0) {
return Math.abs(x);
}
while (y != 0) {
int tmp = y;
y = x % y;
x = tmp;
}
return x;
}
@Override
public boolean equals(Object o) {
Slope slope = (Slope) o;
return n == slope.n && m == slope.m;
}
@Override
public int hashCode() {
return Objects.hash(n, m);
}
}
public boolean checkStraightLine(int[][] coordinates) {
Slope slope = null;
for (int i = 1; i < coordinates.length; i++) {
// 略过与coordinates[0]相同的点
if (Arrays.equals(coordinates[0], coordinates[i])) {
continue;
}
// 遇到不同的点了,则可以确定一个斜率
Slope curSlope = new Slope(coordinates[i][1] - coordinates[0][1], coordinates[i][0] - coordinates[0][0]);
// 如果是第一次遇到不同的点,则可以确定直线的斜率;否则判断一下当前点与之前确定的斜率是否吻合
if (slope == null) {
slope = curSlope;
} else if (!slope.equals(curSlope)) {
return false;
}
}
// 如果走到这儿slope是null,则说明所有点都重合,此时不能确定一条直线,所以返回false;否则返回true
return slope != null;
}
}
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。