leecode->Max Points on a Line

每天一刷,强迫学习

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

看到题目就懵了,多年不学数学的下场:输入一串带坐标的点,求二维平面中在一条直线上的最多的点的个数。


思路:

1、首先判断一个点是否在一条直线上的方法,从数学上来讲当然是计算y=kx+b的常量数字了,但是很明显k、b很有可能是浮点数,而浮点数计算判断相等在计算机中从来不是简单的事情。谢天谢地,题目中的坐标均为int类型,这样我们就可以利用三个点之间的向量是否两两平行来计算;

2、讨论三个点在一条直线上的方法:

a)其中两个点或三个点重合,例如输入为(1,1)(1,1)(2,2),此时三点必在一条直线上;

b)三个点均不重合,但是三个点之间的向量中某个坐标值均为0,比如(1,1)(2,1)(3,1),其中两个向量为(-1,0)(-2,0),如果两个向量横坐标方向或者纵坐标方向均为0,则此三点在一条直线上;

c)三个点均不重合,但是三个点之间的向量中某个坐标值为0,其他不为零,则三点必然不再一条直线上;

d)b、c两步的判断是因为向量为0时无法用x1/y1=x2/y2来计算,均不为零时可以转化为x1*y2==x2*y1来判断是否为真,为真则在一条直线上,否则不在一条直线上。

3、接下来就是用两个不同位置的点确认一条直线,两个for循环内判断两个点是否是同一个点,如果是则continue,不是则遍历剩余所有的点。遍历过程中如果判断是在同一条直线上则值+1;

4、从数组中选出点最多的那条线,将结果返回。


总结:

1、思路清晰比强写代码好的多;

2、如果想不出来,画画也是好的;

3、写代码过程中没有考虑两个点是同一个点的情况、输入只有一个点的情况、所有点都是一个点的情况,造成多次返工。

4、效率上有些问题,用来确定直线的两个点遍历到第三个点的时候,可以不再判断三个点与前两个点确定的直线的情况。如此一来效率提高,但代码较为复杂。实际生产中需考虑输入的规模,有必要就加以改进,规模不大也不必花太大的心思。


看着自己写的代码想起了微软的那个笑话:费劲心思偷窃出来windows最后几页源代码,发现全是}}}}}}}}}}}}}}}


/**
 * 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 boolean comp(Point a, Point b, Point c) {
		if((a.x == b.x && a.y==b.y)||(c.x == b.x && c.y==b.y)||(a.x == c.x && a.y==c.y)){
			return true;
		}
		int dirX1 = a.x - b.x;
		int dirX2 = a.x - c.x;
		int dirY1 = a.y - b.y;
		int dirY2 = a.y - c.y;

		if ((dirX1 == 0 && dirX2 == 0) || (dirY1 == 0 && dirY2 == 0)) {
			return true;
		} else if ((dirX1 == 0 && dirX2 != 0) || (dirX1 != 0 && dirX2 == 0)
				|| (dirY1 == 0 && dirY2 != 0) || (dirY1 != 0 && dirY2 == 0)) {
			return false;
		} else {
			int m1 = dirX1 * dirY2;
			int m2 = dirX2 * dirY1;
			if (m1 == m2)
				return true;
			else
				return false;
		}
	}


	public int maxPoints(Point[] points) {
		int len = points.length;
		int[][] sizeOneLine = new int[len][len];
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len; j++) {
				sizeOneLine[i][j] = 2;
			}
		}
		
		if (len == 2 || len == 1) {
			return len;
		}
		boolean isOnePoint = true;
		for(int i = 1; i < len; i++){
		    if(points[0].x != points[i].x || points[0].y != points[i].y ){
		        isOnePoint = false;
		        break;
		    }
		}
		if(isOnePoint){
		    return len;
		}
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len; j++) {
				if(points[i].x == points[j].x && points[i].y==points[j].y)
					continue;
				for (int m = 0; m < len; m++) {
					if (i != j && i != m && j != m) {
						if (comp(points[i], points[j], points[m])) {
							sizeOneLine[i][j] += 1;
						}
					}
				}
			}
		}
		int temp = 0;
		for(int i=0;i<len;i++){
			for(int j=0;j<len;j++){
				if(temp < sizeOneLine[i][j]){
					temp = sizeOneLine[i][j];
				}
			}
		}
		return temp;
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值