/** * 思路:在任意两点之间画一条无线长的直线,用散列表追踪那条直线出现的次数最多。时间复杂度O(N*N) * 注意: * 1)用斜率和y轴截距来确定是否是同一条直线。 * 2)浮点数不一定能用二进制数准确表示,因此检查两个浮点数的差值是否在某个极小值(epsilon)内。 * 3)对于散列表而言,斜率相等,未必散列值相同。因此,将斜率减去一个极小值,并以得到的结果flooredSlope作为散列键。 * 4)取得所有可能相等的直线,搜索三个位置:flooredSlope,flooredSlope-epsilon,flooredSlope+epsilon。 * @param points * @return */ public static MyLine1 findBestLine(GraphPoint[] points){ MyLine1 bestLine=null; int bestCount=0; HashMap<Double,ArrayList<MyLine1>> lineBySlope=new HashMap<Double, ArrayList<MyLine1>>(); for(int i=0;i<points.length-1;i++){ for(int j=i+1;j<points.length;j++){ MyLine1 line=new MyLine1(points[i],points[j]); insertLine(lineBySlope,line); int count=countEquivalentLines(lineBySlope,line); if(count>bestCount){ bestCount=count; bestLine=line; } } } return bestLine; } private static int countEquivalentLines(HashMap<Double, ArrayList<MyLine1>> lineBySlope, MyLine1 line) { double key=line.floorToNearestEpsilon(line.slope); double eps=line.epsilon; int count=countEquivalentLines(lineBySlope.get(key), line)+countEquivalentLines(lineBySlope.get(key-eps), line)+ countEquivalentLines(lineBySlope.get(key+eps), line); return count; } public static int countEquivalentLines(ArrayList<MyLine1> lines,MyLine1 line){ if(lines==null) return 0; int count=0; for(MyLine1 paralleLine:lines){ if(paralleLine==line) count++; } return count; } private static void insertLine(HashMap<Double, ArrayList<MyLine1>> lineBySlope, MyLine1 line) { ArrayList<MyLine1> lines=null; double key=line.floorToNearestEpsilon(line.slope); if(!lineBySlope.containsKey(key)){ lines=new ArrayList<MyLine1>(); lineBySlope.put(key, lines); }else{ lines=lineBySlope.get(key); } lines.add(line);//注意此处添加的用法 } class MyLine1{ public static double epsilon=0.0001; public double slope,intercept; public boolean infiniteSlope=false; public MyLine1(GraphPoint p,GraphPoint q){ if(Math.abs(p.x-q.x)>epsilon){//两个点的x坐标不同 slope=(p.y-q.y)/(p.x-q.x);//斜率 intercept=p.y-slope*p.x;//y轴截距 }else{ infiniteSlope=true; intercept=p.x;//x轴截距 } } public double floorToNearestEpsilon(double d){ int r=(int) (d/epsilon);//使原d保留小数位后的4位(epsilon=0.0001) return ((double)r)*epsilon; } public boolean isEquivalent(MyLine1 line){ if((slope==line.slope)&&(intercept==line.intercept)&&(infiniteSlope==line.infiniteSlope)) return true; return false; } public boolean isEquivalent(double a,double b){ return Math.abs(a-b)<epsilon; } } class GraphPoint{ int x; int y; public GraphPoint(int x,int y){ this.x=x; this.y=y; } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
9.7数学与概率(四)——在二维平面上,有一些点,请找出经过点数最多的那条线
原文地址:http://blog.csdn.net/shangqing1123/article/details/47357583