对于给定的n个位于同一二维平面上的点,求最多能有多少个点位于同一直线上
import java.util.*;
/*
* public class Point {
* int x;
* int y;
* }
*/
public class Solution {
/**
*
* @param points Point类一维数组
* @return int整型
最简单直接的思路:
1) 选择第一个点A1
2) 选择第二个点A2, 和第一个点构成一条直线,
3) 遍历剩下的n-2个点Ai, 判断Ai与A1构成的直线是否与A2与A1构成的直线保持一致,若是,则A1A2直线上的点数就+1;
4)每次求完A1A2直线上的最大点数, 和结果取最大值. 遍历结束就是结果
*/
public int maxPoints (Point[] points) {
// write code here
if(points==null||points.length==0) return 0;
if(points.length<3) return points.length;
int maxPoints = 2;
for(int i=0;i<points.length;i++){
int x1 = points[i].x;
int y1 = points[i].y;
for(int j = i+1;j<points.length;j++){
int x2 = points[j].x;
int y2 = points[j].y;
int max = 2;
for(int k =0;k<points.length;k++){
if(k==i || k==j) continue;
int x3 = points[k].x;
int y3 = points[k].y;
boolean flag;
if(x1==x2){
flag= x3==x1;
}else if(y1==y2){
flag = y3==y1;
}else{
flag = (y2-y1)*(x3-x1) == (y3-y1)*(x2-x1);//三点式直线方程
}
if(flag) max++;
}
maxPoints=Math.max(maxPoints,max);
}
}
return maxPoints;
}
} import java.util.*;
public class Solution {
public int maxPoints(Point[] points) {
int length = points.length;
if(length == 0)
return 0;
else if(length == 1)
return 1;
int maxOfAll = 0;//全局单条线上最多的点数量
for(int i = 0;i<length;i++){
int curMax = 1;
//针对点i固定的情况,只要斜率相等,则肯定是在一条直线上!
HashMap<Double,Integer> gradientOfPoint_ij=new HashMap<>();//这是记录斜率的!
int verticalPointsSituation = 0; //两个点不重复,但是构成垂直线
int samePointsSituation = 0; //2个点为重复点
for(int j = 0;j<length;j++){
if(j!=i){
double x1 = points[i].x - points[j].x;
double y1 = points[i].y - points[j].y;
if(x1 == 0 && y1 == 0){ //重复点
samePointsSituation++;//最后加在i点结果之上
}else if(x1 == 0){ //垂直点
if(verticalPointsSituation == 0)
verticalPointsSituation = 2;
else
verticalPointsSituation++;
curMax =Math.max(verticalPointsSituation,curMax);
}else{
double k = y1/x1; //计算斜率
if(! gradientOfPoint_ij.containsKey(k))
gradientOfPoint_ij.put(k,2);
else
gradientOfPoint_ij.put(k,gradientOfPoint_ij.get(k)+1);
curMax =Math.max(gradientOfPoint_ij.get(k),curMax);
}
}
}
maxOfAll =Math.max(maxOfAll,curMax+samePointsSituation);
}
return maxOfAll;
}
} import java.util.*;
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
public class Solution {
//计算最大公因数
public int ***(int x, int y){
if(y==0){
return x;
}else{
return ***(y, x%y);
}
}
public int maxPoints(Point[] points) {
//corner case
if(points==null)return 0;
if(points.length<=2)return points.length;
int maxFinal = 0;
//每个点
for(int i=0; i<points.length;i++){
HashMap<Integer, HashMap<Integer, Integer>> map = new HashMap<>();
int max = 0;
int samePoint =0;
//i点的后面的另外一个j点
for(int j=i+1; j<points.length;j++){
//算他们的dx和dy
int dx = points[j].x-points[i].x;
int dy = points[j].y-points[i].y;
//如果是重合的点
if(dx==0 &&dy==0){
samePoint+=1;
//跳出循环,走下一个j点
continue;
}
//计算最大公因数
int GCD = ***(dx,dy);
//简化dx和dy,不需要计算出dx/dy因为不准确,所以简化dx和dy来获得一对dx-dy
//拥有相同的一对dx-dy,证明点在同一线上
if(GCD!=0){
dx/=GCD;
dy/=GCD;
}
//contains the x
if(map.containsKey(dx)){
//contains x-y pair, increase by 1
if(map.get(dx).containsKey(dy)){
map.get(dx).put(dy, map.get(dx).get(dy)+1 );
//create new x-y pair
}else{
map.get(dx).put(dy,1);
}
//add new x-y pair
}else{
HashMap<Integer,Integer> newPair = new HashMap<>();
newPair.put(dy,1);
map.put(dx,newPair);
}
//get the max
max= Math.max(max,map.get(dx).get(dy));
}
maxFinal = Math.max(maxFinal,max+samePoint+1);
}
return maxFinal;
}
} public class Solution {
public int maxPoints(Point[] points) {
if(points.length < 2) {
return points.length;
}
int max = 2;
for(int i = 0; i < points.length - 1; i++) {
int base = 1;
for(int j = i + 1; j < points.length; j++) {
int count = 2;
if(points[i].x == points[j].x && points[i].y == points[j].y) {
base++;
max = base > max ? base : max;
} else {
for(int k = 0; k < points.length; k++) {
if(k == i || k == j) {
continue;
}
count += isLine(points[i], points[j], points[k]) ? 1 : 0;
}
max = count > max ? count : max;
}
}
}
return max;
}
boolean isLine(Point p1, Point p2, Point p3) {
return (p1.x - p2.x) * p3.y == (p1.y - p2.y) * (p3.x - p2.x) + p2.y * (p1.x - p2.x);
}
}

点共线,那么最容易想到的思路就是确定斜率,斜率相同不就共线了。但是还有两点特殊情况需要考虑,二是当两个点重合时,无法确定一条直线,但这也是共线的情况,需要特殊处理。二是斜率不存在的情况,由于两个点(x1, y1)和(x2, y2)的斜率k表示为(y2 - y1) / (x2 - x1),那么当x1 = x2时斜率不存在,这种共线情况需要特殊处理。这里我对重合的情况,斜率不存在的情况以及斜率为0的情况进行了讨论,因为这比较好处理,所以处理一下斜率为0的没什么问题。最后就是通用情况,代码如下:
class Solution {
public int maxPoints(Point[] points) {
if(points == null){
return 0;
}
if(points.length <= 2){
return points.length;
}
Map map = new HashMap();
int result = 0;
for(int i=0;i<points.length;i++){
map.clear();
int overlap = 0;
int vertical = 0;
int horizon = 0;
int max = 0;
double rate = 0.0;
for(int j=i+1;j<points.length;j++){
double gapx = new Double(points[i].x) - new Double(points[j].x);
double gapy = new Double(points[i].y) - new Double(points[j].y);
if(gapx == 0 && gapy == 0){
overlap++;
continue;
}else if(gapx == 0){
vertical++;
max = Math.max(max,vertical);
}else if(gapy == 0){
horizon++;
max = Math.max(max,horizon);
}else{
rate = gapy/gapx;
if(map.containsKey(rate)){
map.put(rate,map.get(rate)+1);
}else{
map.put(rate,1);
}
max = Math.max(max,map.get(rate));
}
}
result=Math.max(result, max+overlap+1);
}
return result;
}
}虽然可以在牛客上通过,但是这个思路在leetcode上已经不行了,它给的例子是:
Input [[0,0],[94911151,94911150],[94911152,94911151]]
Output 3
Expected 2我们注意到,由于精度丢失问题,我们算出来的斜率竟然是一样的了,所以这个程序错误地认为这三个点都共线了。因此错误。那怎么办呢?
由于通过斜率来判断共线需要用到除法,而用double表示的双精度小数在有的系统里不一定准确,为了更加精确无误的计算共线,我们应当避免除法,从而避免无线不循环小数的出现,那么怎么办呢,我们把除数和被除数都保存下来,不做除法,但是我们要让这两数分别除以它们的最大公约数,这样例如8和4,4和2,2和1,这三组商相同的数就都会存到一个映射里面,同样也能实现我们的目标。
class Solution {
public int maxPoints(Point[] points) {
if(points == null){
return 0;
}
if(points.length <= 2){
return points.length;
}
//key为每个数组除以最大公约数后的结果,比如[8,4],[4,2],[2,1]最后都变成[2,1]存储
Map,Integer> map = new HashMap();
int result = 0;
for(int i=0;i<points.length;i++){
//每次循环完毕要清空map,否则会把上次统计结果带到下一次循环来
map.clear();
//重复个数,自己算重复元素,所以初始元素为1
int dup = 1;
int max = 0;
for(int j=i+1;j<points.length;j++){
//计算出两者间隔
int x = points[i].x - points[j].x;
int y = points[i].y - points[j].y;
//重合的话就将dup加一
if(x == 0 && y == 0){
dup++;
continue;
}
//计算最大公约数
int d = gcd(x, y);
Map tmpMap = new HashMap();
tmpMap.put(x/d,y/d);
//次数
map.put(tmpMap, map.getOrDefault(tmpMap, 0) + 1);
//每次都将最大的放到max中,避免最后还要遍历判断map中最大次数
max = Math.max(max,map.get(tmpMap));
}
//最后的结果就是map+dup
result = Math.max(result,max+dup);
}
return result;
}
public int gcd(int a, int b) {
return (b == 0) ? a : gcd(b, a % b);
}
}
//比例法 public static int maxPoints2(Point[] points) { //排除不足3个点的情况 if(points.length <= 2)return points.length; int max = 2; for(int i = 0;i < points.length - 1; i++){ for(int j = i + 1;j < points.length; j++){ int count = 2; //斜率不为无穷 if((points[i].x != points[j].x)){ int m = 0; double y = 10000.0 * (double)(points[i].y - points[j].y); double x = 10000.0 * (double)(points[i].x - points[j].x); while(m < points.length){ if(m != i && m != j){ double y2 = 10000.0 * (double)(points[i].y - points[m].y); double x2 = 10000.0 * (double)(points[i].x - points[m].x); if(isEqual(x2 * y, y2 * x)) count++; } m++; } if(count > max) max = count; } //斜率为无穷大 else{ int m = 0; while(m < points.length){ if(m != i && m != j && points[m].x == points[i].x) count++; m++; } if(count > max) max = count; } } } return max; }
public class maxPoints { public static class Point { int x; int y; Point() {x = 0;y = 0;} Point(int a, int b) {x = a;y = b;} } public static void main(String[] args) { // TODO Auto-generated method stub //Point[] points = {new Point(1,2), new Point(1,3), new Point(2,4), new Point(3,6), new Point(2,6)}; Point[] points = {new Point(3,10), new Point(0,2), new Point(0,2), new Point(3,10)}; System.out.println(maxPoints(points)); } public static int maxPoints(Point[] points) { //排除不足3个点的情况 if(points.length <= 2)return points.length; int max = 2; for(int i = 0;i < points.length - 1; i++){ for(int j = i + 1;j < points.length; j++){ int count = 2; //斜率不为无穷 if((points[i].x != points[j].x)){ double k = (double)(points[i].y - points[j].y) / (points[i].x - points[j].x); double b = points[i].y - points[i].x * k; int m = 0; while(m < points.length){ if(m != i && m != j && isEqual(points[m].y, k * points[m].x + b)) count++; m++; } if(count > max) max = count; } //斜率为无穷大 else{ int m = 0; while(m < points.length){ if(m != i && m != j && points[m].x == points[i].x) count++; m++; } if(count > max) max = count; } } } return max; } //浮点数相等比较 public static boolean isEqual(double x1, double x2){ if((x1 - x2 <= 0.0000001) && (x1 - x2 >= -0.0000001)){ return true; }else{ return false; } }
}
import java.util.*;
public class Solution {
public int maxPoints(Point[] points) {
if(points.length == 1 || points.length == 0 || points.length==2) {
return points.length;
}
int result=1;
for(int i=0;i<points.length;i++) {
int curMax=1,coincide=0;
Map<String, Integer> slopeMap=new HashMap<String, Integer>();
String k="";
for(int j=0;j<points.length;j++) {
// compute slope between two points
if(i != j) {
// same points
if (points[i].x == points[j].x && points[i].y == points[j].y) {
coincide++;
continue;
// vertical
}else if (points[i].x == points[j].x) {
k = "vertical";
}else if (points[i].y == points[j].y) {
k = "horizontal";
} else{
k = computeSlope(points[i], points[j]);
}
if (slopeMap.containsKey(k)) {
slopeMap.put(k, slopeMap.get(k)+1);
}else {
slopeMap.put(k,2);
}
curMax = Math.max(slopeMap.get(k),curMax);
}
}
result = Math.max(result, curMax+coincide);
}
return result;
}
private String computeSlope(Point p1, Point p2) {
int x=p1.x-p2.x;
int y=p1.y-p2.y;
int gcd=computeGcd(x,y);
return (y/gcd+"")+"/"+(x/gcd+"");
}
private int computeGcd(int m, int n) {
if (m < n) {
int temp = m;
m = n;
n = temp;
}
while (m % n != 0) {
int temp = m % n;
m = n;
n = temp;
}
return n;
}
}
主体方法没什么区别,在存储斜率方面直接用最简分数形式来表示两点之间的斜率,完全避免float引起的精度误差
ret = Math.max(ret, max + dup);//这里最大值的处理是在循环I中完成的,用一个全局变量Ret保证最终结果的最大性,针对一个固定点选择合适它的最大值就简单多了。我觉得重合Dup初始化为1而不是0是很有必要的。避免出现输入两个相同的点却输出1的错误边界情况发生}
public int maxPoints(Point[] points) {
if (points.length == 0) {
return 0;
}
if (points.length == 1) {
return 1;
}
int max = 0;
double k = 0.0;// 斜率
for (int i = 0; i < points.length; i++) {
Map<Double, Integer> map = new HashMap<Double, Integer>();// 保存斜率和节点数量
int dup = 0;// 重复的节点
int tempmax = 1;
for (int j = i + 1; j < points.length; j++) {
double x1 = points[j].x - points[i].x;
double y1 = points[j].y - points[i].y;
if (x1 == 0 && y1 == 0) {// 重复的节点
dup++;
} else {
if (x1 == 0) {// 垂直
k = Double.MAX_VALUE;
} else if (y1 == 0) {
k=0.0;
} else {
k = 1.0 * (y1 / x1);// 计算斜率
}
int num;
if (map.get(k) != null) {
num = map.get(k) + 1;
} else {
num = 2;
}
map.put(k, num);
tempmax = num > tempmax ? num : tempmax;
}
}
max = (tempmax + dup) > max ? tempmax + dup : max;
}
return max;
}
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
public class Solution {
public int maxPoints(Point[] points) {
/*
一、基于的原理:
A与B在同一条直线上且B与C在同一条直线上,那么若AB与BC同斜率
则A、B、C三点是否共线即有
deta(ABx)*deta(BCy)=deta(ABy)*deta(BCx)
二、算法思想:
同直线上点的个数为与模板点重合的点数+在模板直线上的点数
固定模板点,累计与模板点重合的点数
固定模板直线,累计在模板直线上的点数
更新最大值
*/
if (points.length<=2){
return points.length;
}else{
int max=2;
for(int i=0;i<points.length;i++){
Point Aitem = points[i];
int point_num = 1;//累计同直线上不同点的个数,至少存在点A
int Adup = 0;//与A重合的个数
for(int j=i+1;j<points.length;j++){
Point Bitem = points[j];
int ABxdiffer = Bitem.x-Aitem.x;
int ABydiffer = Bitem.y-Aitem.y;
if (ABxdiffer==0 && ABydiffer==0){
//累计与A重合的点数
Adup++;
}else{
//假定A与B同直线
point_num++;
for(int k=j+1;k<points.length;k++){
Point Citem = points[k];
int BCxdiffer = Citem.x-Bitem.x;
int BCydiffer = Citem.y-Bitem.y;
if (ABxdiffer*BCydiffer==ABydiffer*BCxdiffer){
//若C与A重合或C与B重合或AB线与BC线重合,
//均满足deta(ABx)*deta(BCy)==deta(ABy)*deta(BCx)
//则A、B、C三点共线
point_num++;
}
}
max = max<(point_num+Adup)?(point_num+Adup):max;
point_num = 1;
}
}
max = max<(point_num+Adup)?(point_num+Adup):max;
}
return max;
}
}
}
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
import java.util.HashMap;
import java.util.Map;
/**
* 逻辑概述:
* 通过穷举所有组合,判断共线的最多有几个点。
* 通过斜率比较,相同的则为共线
* 斜率采用GCD算法
*/
public class Solution {
public int maxPoints(Point[] points) {
int result = 0;
if (points == null) return result;
if (points.length <= 2) return points.length;
int max = Integer.MIN_VALUE;
for (int i = 0; i < points.length; i++) {
Point a = points[i];
HashMap<String,Integer> map = new HashMap<>();
int addIndex = 0;
//求出所有斜率,相同即为同一条线
for (int j = 0; j < points.length; j++) {
if (i == j) continue;
Point b = points[j];
if (isSame(a,b)) {
addIndex++;
} else {
String tempSlope = slope(a,b);
if(map.get(tempSlope) != null) {
map.put(tempSlope,map.get(tempSlope) + 1);
} else {
map.put(tempSlope,1);
}
}
}
//同一条线最多点的存入max
if (map.size() != 0) {
for (Map.Entry<String,Integer> entry : map.entrySet()) {
if ((entry.getValue() + 1 + addIndex) > max) {
max = entry.getValue() + 1 + addIndex;
}
}
} else {
max = addIndex + 1;
}
}
return max;
}
private boolean isSame(Point a,Point b) {
if ((a.x == b.x) && (a.y == b.y)) {
return true;
}
return false;
}
/**
* 求两个点的斜率
*/
private String slope(Point a, Point b){
int ax = a.x;
int ay = a.y;
int bx = b.x;
int by = b.y;
//flag用于标记正负,true为正,false为负
boolean flag = true;
int num1 = ax - bx;
int num2 = ay - by;
if (num1 == 0) {
return "|";
}
if (num2 == 0) {
return "—";
}
//同正同负时为正
if ((num1>0 && num2>0) || (num1<0 && num2<0)) {
flag = true;
}else {
flag = false;
}
//将负转换为正
if (num1 < 0){
num1 = 0 - num1;
}
if (num2 < 0){
num2 = 0 - num2;
}
int ***Num = ***(num1,num2);
String result = num1/***Num + "/" + num2/***Num;
if (!flag) {
result = result + "-";
}
return result;
}
/**
* 欧几里德算法,计算两个整数a,b的最大公约数
*/
private int ***(int num1, int num2) {
if (num2 == 0) {
return num1;
}
return ***(num2,num1%num2);
}
}
public class Solution {
public int maxPoints(Point[] points) {
if(points.length<=2)return points.length;
int result = 0;
for(int i=0;i<points.length;i++){
int flag = 0;//用于检测重合点
for(int j=i+1;j<points.length;j++){
int num = flag+2;
int ABx = points[i].x - points[j].x;
int ABy = points[i].y - points[j].y;
if(ABx==0&&ABy==0){
flag++;
if(num>result)result=num;
continue;
}
for(int k=j+1;k<points.length;k++){
int BCx = points[j].x - points[k].x;
int BCy = points[j].y - points[k].y;
if(ABx*BCy==ABy*BCx)num++;
}
if(num>result)result=num;
}
}
return result;
}
}
/**
相同的点竟然算多个,这一点醉了。。。
利用斜率。具体说是每一个点i,与其前面所有点(0 ~ i-1)的斜率。
如果其中有两个斜率相同,因为它们都经过i,所以它们就在同一条线上。
最后,统计经过每个点有多少最多的相同斜率就找出来了。
*/
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
public class Solution {
public int maxPoints(Point[] points) {
int length = points.length;
if(length==0||length==1||length==2)return length;
float gradients[][] = new float[length][length];
Map<Float,Integer> map[] = new Map[length];
int sames[] = new int[length];
for(int i=0;i<length;++i){
float tmp;
map[i]=new HashMap<Float, Integer>();
for(int j=0;j<=i;++j){
if(j==i)gradients[i][j]=tmp=Float.MAX_VALUE; //代表两个点相同
else{
if(points[i].x==points[j].x) {
if(points[i].y == points[j].y) {
sames[i]++; // 代表点i前面i-1个点中有多少个相同的点
gradients[i][j]=tmp=Float.MAX_VALUE;
}
else gradients[i][j]=tmp=Float.MIN_VALUE; //代表斜率为无穷
}
else gradients[i][j]=tmp=(float)(points[i].x-points[j].x)/ (float)(points[i].y-points[j].y);
}
if(tmp!=Float.MAX_VALUE){
Integer t = map[i].get(tmp);
if(t==null)t=0;
map[i].put(tmp,t+1);
}
}
}
int bigest=0;
for(int i=0;i<length;++i){
int same=sames[i];
if(same>bigest){
bigest=same;
}
for ( int m : map[i].values()){
if(m==Float.MAX_VALUE)continue;
int tmp = m+same;
if (tmp >bigest)
bigest=tmp;
}
}
return bigest+1; // 别忘了把此点本身加上
}
} /**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
//在一个2D平面上有N个点,然后寻找在一条直线上的最大点的个数
//解法:
//穷举,按照斜率相等去计算:斜率相等则说明2个点在一条直线上
import java.util.*;
public class Solution {
public int maxPoints(Point[] points) {
if(points == null||points.length == 0){
return 0;
}
if(points.length <= 2){
return points.length;
}
//float为斜率,int为该斜率下的node的个数
HashMap<Float,Integer> hashMap = new HashMap<Float,Integer>();
//定义同一直线上的node的最大值
int maxCount = 0;
for(int i = 0;i < points.length;i++){
hashMap.clear();
//用于统计重复点的个数,初试为1(将现在正遍历的node计算进去)
int duplicate = 1;
for(int j = 0;j < points.length;j++){
if(i == j){
continue;
}
if(points[i].x == points[j].x && points[i].y == points[j].y){
//遇到重复的node,则也计算进同一条直线中的node
++ duplicate;
continue;
}
//计算斜率
float k = (float)(points[i].y - points[j].y)/(points[i].x - points[j].x);
//保存记录
if(hashMap.containsKey(k)){
hashMap.put(k,hashMap.get(k)+1);
}else{
hashMap.put(k,1);
}
}
//遍历hashMap,得到node个数的最大值
if(hashMap.size()==0){
maxCount = duplicate;
}else{
Iterator iter = hashMap.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry = (Map.Entry) iter.next();
Integer val = (Integer)entry.getValue();
if(val+duplicate > maxCount){
maxCount = val+duplicate;
}
}
}
}
return maxCount;
}
}