No.149 Max Point on a Line
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
尝试1:考虑不周,一条直线上的点会重复计数,但没找到解决方法【wrong】
Input: [[0,0],[-1,-1],[2,2]]
Output: 4
Expected: 3
1 /**
2 * Definition for a point.
3 * struct Point {
4 * int x;
5 * int y;
6 * Point() : x(0), y(0) {}
7 * Point(int a, int b) : x(a), y(b) {}
8 * };
9 */
10 class Solution
11 {
12 public:
13 int maxPoints(vector<Point>& points)
14 {
15 //输入:二维平面上的一组点
16 //输出:同一条直线上的点的最大数量
17 //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
18 // 将得到的数据存到map中:key为斜率,value为该斜率的点的个数
19 int count = points.size() ;
20 if( count == 0)
21 return 0;
22 if( count == 1)
23 return 1;
24 if( count == 2)
25 return 2;
26
27 map<double, int> result;
28 double slope;
29 for(int i=0; i< count ; i++)
30 for(int j = i+1; j<count; j++)
31 {
32 if(points[i].x == points[j].x)
33 slope = numeric_limits<double>::max();
34 else
35 slope = (points[i]. y - points[j]. y)/(points[i]. x - points[j]. x);//除法!!分母
36 if(result.find(slope) == result.end())
37 result[slope] = 2;
38 else
39 result[slope]++;
40 }
41
42 int max = 0;
43 for(auto const i : result)
44 {
45 if(i.second > max)
46 max = i.second;
47 }
48 return max;
49 }
50
51 };
尝试2:【几次提交,总是有点小问题】
输入:二维平面上的一组点
输出:同一条直线上的点的最大数量
思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合【可以去重】
1 /**
2 * Definition for a point.
3 * struct Point {
4 * int x;
5 * int y;
6 * Point() : x(0), y(0) {}
7 * Point(int a, int b) : x(a), y(b) {}
8 * };
9 */
10 class Solution
11 {
12 public:
13 int maxPoints(vector<Point> &points)
14 {//输入:二维平面上的一组点
15 //输出:同一条直线上的点的最大数量
16 //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
17 // 将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合
18 //const double INFINITY = numeric_limits<double>::max();//无穷大斜率,即与y轴平行!!!//leetcode不支持
19 //用INT_MAX
20 int count = points.size() ;
21 if(count < 3)
22 return count;
23 map<double, set<int>> result;
24 double slope;
25 int max = 0;
26 int SamePointCount = 0;//记录与当前定点i重合的点的数量(不包括i)
27 for(int i=0; i< count; i++)
28 {
29 result.clear();
30 SamePointCount = 0;
31 for(int j = 0; j<count; j++)
32 {
33 if(i==j)
34 continue;
35 if(points[i].x == points[j].x && points[i].y == points[j].y)
36 {
37 SamePointCount++;
38 continue;
39 }
40 if(points[i].x == points[j].x)
41 slope = INT_MAX;
42 //此时,即使斜率相同,也不在同一条直线上,还与x(截距)有关
43 else
44 slope = (double)(points[i]. y - points[j]. y)/(double)(points[i]. x - points[j]. x);//除法!!分母
45 //精度问题导致错误!!!
46 result[slope].insert(i);
47 result[slope].insert(j);//set重复插入会无视
48 }
49 for(auto const &i : result)
50 {
51 if(i.second.size()+SamePointCount > max)
52 max = i.second.size()+SamePointCount;
53 }
54
55 }
56 return max;
57 }
58 };
最终:
之前的想法与思路都是有问题的,最开始想到的,是统计每两个点确定的斜率,用哈希表来保存;之后发现,在统计斜率的时候,会有点被重复计算,就想到用一个set来保存同一斜率的点的集合;再提交,又出现问题,以为是无穷斜率需要考虑截距,其实,其他的都需要,就想,难道,要以斜率和截距来确定一条直线再统计??!!太麻烦了。
之后,参考网上其他人的做法,找到一种比较好的做法:
任意一条直线都可以表述为:y = ax + b
假设,有两个点(x1,y1), (x2,y2),如果它们都在这条直线上,则有y1 = kx1 +b;y2 = kx2 +b
由此可以得到关系,k = (y2-y1)/(x2-x1)。即如果点c和点a的斜率为k, 而点b和点a的斜率也为k,可以知道点c和点b也在一条线上。
关键在于要有一个定点:
取定一个点points[i], 遍历其他所有节点, 然后统计斜率相同的点数,并求取最大值即可。
【该遍历要遍历所有,不是从i+1开始】
注意事项:
1、在编程过程中,若不需要,就不要存储过程或其他结果,浪费空间和时间
2、各种测试用例的思考,多考虑,因为这个,提交好多次;要自己去想,做调试,不要等提交后,再。。
3、修改之后,一定要做回归测试!!!
4、特殊情况:
- 重复点【不要当成斜率无穷大】
- 涉及除法,分母为0,斜率无穷大的情况,即与y轴平行
- 只有相同的点,此时直接返回即可
- 计算精度问题
最终版本:
1 #include "stdafx.h" 2 #include <vector> 3 #include <map> 4 #include <time.h> 5 #include <iostream> 6 #include <limits> 7 #include <set> 8 using namespace std; 9 10 struct Point 11 { 12 int x; 13 int y; 14 Point(): x(0),y(0) {} 15 Point(int a, int b) : x(a),y(b) {} 16 }; 17 class Solution 18 { 19 public: 20 int maxPoints(vector<Point> &points) 21 {//输入:二维平面上的一组点 22 //输出:同一条直线上的点的最大数量 23 //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己 24 // 将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合 25 // const double INFINITY = numeric_limits<double>::max();//无穷大斜率,即与y轴平行 26 //leetcode不支持 27 int count = points.size() ; 28 if(count < 3) 29 return count; 30 31 map<double, int> result; 32 double slope; 33 int max = 0; 34 int SamePointCount = 0;//记录与当前定点i重合的点的数量(不包括i) 35 for(int i=0; i< count; i++) 36 { 37 result.clear(); 38 SamePointCount = 0; 39 for(int j = 0; j<count; j++)// 40 { 41 if(i==j)//跳过相同的点 42 continue; 43 if(points[i].x == points[j].x && points[i].y == points[j].y) 44 { 45 SamePointCount++; 46 continue; 47 } 48 if(points[i].x == points[j].x) 49 slope = INT_MAX; 50 //此时,即使斜率相同,也不在同一条直线上,还与x(截距)有关 51 else 52 slope = (double)(points[i]. y - points[j]. y)/(double)(points[i]. x - points[j]. x);//除法!!分母 53 //精度问题导致错误!!! 54 if(result.find(slope) == result.end()) 55 result[slope]=2;//包括该定点 56 else 57 result[slope]++; 58 } 59 if(result.size() == 0)//极端:只有重复点!!! 60 return SamePointCount+1; 61 62 for(auto const &i : result) 63 { 64 if(i.second+SamePointCount > max) 65 max = i.second+SamePointCount; 66 } 67 68 } 69 return max; 70 } 71 72 void generatePoints(int n , vector<Point> &points) 73 { 74 srand(time(0)); 75 Point p; 76 for(int i=0; i<n; i++) 77 { 78 p.x = rand(); 79 p.y = rand(); 80 points.push_back(p); 81 } 82 } 83 }; 84 85 int main() 86 { 87 Solution sol; 88 vector<Point> points; 89 // sol.generatePoints(6,points); 90 /* 91 points.push_back(Point());//点(0,0) 92 points.push_back(Point(-1,-1));//点(-1,-1) 93 points.push_back(Point(2,2));//点(2,2) 94 //输出应为3,却输出4,有点重复计算了! 95 */ 96 /* 97 //测试用例:输出应为25 98 Point test[]= {Point(40,-23),Point(9,138),Point(429,115),Point(50,-17),Point(-3,80), Point(-10,33), Point(5,-21), Point(-3,80), Point(-6,-65), Point(-18,26), Point(-6,-65), Point(5,72), Point(0,77), Point(-9,86), Point(10,-2), Point(-8,85), Point(21,130), Point(18,-6), Point(-18,26), Point(-1,-15), Point(10,-2), Point(8,69), Point(-4,63), Point(0,3), Point(-4,40), Point(-7,84), Point(-8,7), Point(30,154), Point(16,-5), Point(6,90), Point(18,-6), Point(5,77), Point(-4,77), Point(7,-13), Point(-1,-45), Point(16,-5), Point(-9,86), Point(-16,11), Point(-7,84), Point(1,76), Point(3,77), Point(10,67), Point(1,-37), Point(-10,-81), Point(4,-11), Point(-20,13), Point(-10,77), Point(6,-17), Point(-27,2), Point(-10,-81), Point(10,-1), Point(-9,1), Point(-8,43), Point(2,2), Point(2,-21), Point(3,82), Point(8,-1), Point(10,-1), Point(-9,1), Point(-12,42), Point(16,-5), Point(-5,-61), Point(20,-7), Point(9,-35), Point(10,6), Point(12,106), Point(5,-21), Point(-5,82), Point(6,71), Point(-15,34), Point(-10,87), Point(-14,-12), Point(12,106), Point(-5,82), Point(-46,-45), Point(-4,63), Point(16,-5), Point(4,1), Point(-3,-53), Point(0,-17), Point(9,98), Point(-18,26), Point(-9,86), Point(2,77), Point(-2,-49), Point(1,76), Point(-3,-38), Point(-8,7), Point(-17,-37), Point(5,72), Point(10,-37), Point(-4,-57), Point(-3,-53), Point(3,74), Point(-3,-11), Point(-8,7), Point(1,88), Point(-12,42), Point(1,-37), Point(2,77), Point(-6,77), Point(5,72), Point(-4,-57), Point(-18,-33), Point(-12,42), Point(-9,86), Point(2,77), Point(-8,77), Point(-3,77), Point(9,-42), Point(16,41), Point(-29,-37), Point(0,-41), Point(-21,18), Point(-27,-34), Point(0,77), Point(3,74), Point(-7,-69), Point(-21,18), Point(27,146), Point(-20,13), Point(21,130), Point(-6,-65), Point(14,-4), Point(0,3), Point(9,-5), Point(6,-29), Point(-2,73), Point(-1,-15), Point(1,76), Point(-4,77), Point(6,-29)}; 99 vector<Point> points(test,test+sizeof(test)/sizeof(Point)); 100 */ 101 /* 102 points.push_back(Point(2,2));// 103 points.push_back(Point(2,2));// 104 points.push_back(Point(2,2));// 105 */ 106 ///* 107 //测试用例:重复点问题,accept=4 108 points.push_back(Point(1,1));//0 109 points.push_back(Point(1,1));//1 110 points.push_back(Point(2,2));//2 111 points.push_back(Point(2,2));//3 112 //*/ 113 114 /* 115 //测试用例:输出应为6 116 points.push_back(Point(0,-12));//0 117 points.push_back(Point(5,2));//1 118 points.push_back(Point(2,5));//2 119 points.push_back(Point(0,-5));//3 120 points.push_back(Point(1,5));//4 121 points.push_back(Point(2,-2));//5 122 points.push_back(Point(5,-4));//6 123 points.push_back(Point(3,4));//7 124 points.push_back(Point(-2,4));//8 125 points.push_back(Point(-1,4));//9 126 points.push_back(Point(0,-5));//10 127 points.push_back(Point(0,-8));//11 128 points.push_back(Point(-2,-1));//12 129 points.push_back(Point(0,-11));//13 130 points.push_back(Point(0,-9));//14 131 */ 132 133 for(auto const &i : points) 134 cout << i.x << " "<<i.y<<endl; 135 cout << sol.maxPoints(points)<<endl; 136 return 0; 137 }
最终不简洁版本:
1 #include "stdafx.h" 2 #include <vector> 3 #include <map> 4 #include <time.h> 5 #include <iostream> 6 #include <limits> 7 #include <set> 8 using namespace std; 9 10 struct Point 11 { 12 int x; 13 int y; 14 Point(): x(0),y(0) {} 15 Point(int a, int b) : x(a),y(b) {} 16 }; 17 class Solution 18 { 19 public: 20 int maxPoints(vector<Point> &points) 21 {//输入:二维平面上的一组点 22 //输出:同一条直线上的点的最大数量 23 //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己 24 // 将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合 25 // const double INFINITY = numeric_limits<double>::max();//无穷大斜率,即与y轴平行 26 int count = points.size() ; 27 if(count < 3) 28 return count; 29 /* 30 if( count == 0) 31 return 0; 32 if( count == 1) 33 return 1; 34 if( count == 2) 35 return 2; 36 */ 37 map<double, int> result; 38 double slope; 39 int max = 0; 40 int SamePointCount = 0;//记录与当前定点i重合的点的数量(不包括i) 41 for(int i=0; i< count; i++) 42 { 43 result.clear(); 44 SamePointCount = 0; 45 for(int j = 0; j<count; j++)// 46 { 47 if(i==j)//跳过相同的点 48 continue; 49 if(points[i].x == points[j].x && points[i].y == points[j].y) 50 { 51 SamePointCount++; 52 continue; 53 } 54 if(points[i].x == points[j].x) 55 slope = INT_MAX; 56 //此时,即使斜率相同,也不在同一条直线上,还与x(截距)有关 57 else 58 slope = (double)(points[i]. y - points[j]. y)/(double)(points[i]. x - points[j]. x);//除法!!分母 59 //精度问题导致错误!!! 60 if(result.find(slope) == result.end()) 61 result[slope]=2;//包括该定点 62 else 63 result[slope]++; 64 } 65 if(result.size() == 0)//极端:只有重复点 66 return SamePointCount+1; 67 68 for(auto const &i : result) 69 { 70 if(i.second+SamePointCount > max) 71 max = i.second+SamePointCount; 72 } 73 74 } 75 return max; 76 /* 77 int max = 0; 78 for(auto const i : result) 79 { 80 if(i.first != INFINITY && i.second.size() > max) 81 //斜率无穷大即与y轴垂直的,要单独计算 82 max = i.second.size(); 83 } 84 if(max >= result[INFINITY].size()) 85 return max; 86 else 87 {//分别计算无穷大斜率的不同截距各有几个点 88 map<int,int> m;//key为截距,即x点坐标,value为数量 89 for(auto i = result[INFINITY].begin(); i != result[INFINITY].end(); i++) 90 {//set没有下标操作 91 if(m.find(points[*i].x) != m.end()) 92 m[points[*i].x] = 1; 93 else 94 m[points[*i].x]++; 95 } 96 for(auto const &i : m) 97 { 98 if(i.second > max) 99 max = i.second; 100 } 101 return max; 102 } 103 */ 104 } 105 106 void generatePoints(int n , vector<Point> &points) 107 { 108 srand(time(0)); 109 Point p; 110 for(int i=0; i<n; i++) 111 { 112 p.x = rand(); 113 p.y = rand(); 114 points.push_back(p); 115 } 116 } 117 }; 118 119 int main() 120 { 121 Solution sol; 122 vector<Point> points; 123 // sol.generatePoints(6,points); 124 /* 125 points.push_back(Point());//点(0,0) 126 points.push_back(Point(-1,-1));//点(-1,-1) 127 points.push_back(Point(2,2));//点(2,2) 128 //输出应为3,却输出4,有点重复计算了! 129 */ 130 /* 131 //测试用例:输出应为25 132 Point test[]= {Point(40,-23),Point(9,138),Point(429,115),Point(50,-17),Point(-3,80), Point(-10,33), Point(5,-21), Point(-3,80), Point(-6,-65), Point(-18,26), Point(-6,-65), Point(5,72), Point(0,77), Point(-9,86), Point(10,-2), Point(-8,85), Point(21,130), Point(18,-6), Point(-18,26), Point(-1,-15), Point(10,-2), Point(8,69), Point(-4,63), Point(0,3), Point(-4,40), Point(-7,84), Point(-8,7), Point(30,154), Point(16,-5), Point(6,90), Point(18,-6), Point(5,77), Point(-4,77), Point(7,-13), Point(-1,-45), Point(16,-5), Point(-9,86), Point(-16,11), Point(-7,84), Point(1,76), Point(3,77), Point(10,67), Point(1,-37), Point(-10,-81), Point(4,-11), Point(-20,13), Point(-10,77), Point(6,-17), Point(-27,2), Point(-10,-81), Point(10,-1), Point(-9,1), Point(-8,43), Point(2,2), Point(2,-21), Point(3,82), Point(8,-1), Point(10,-1), Point(-9,1), Point(-12,42), Point(16,-5), Point(-5,-61), Point(20,-7), Point(9,-35), Point(10,6), Point(12,106), Point(5,-21), Point(-5,82), Point(6,71), Point(-15,34), Point(-10,87), Point(-14,-12), Point(12,106), Point(-5,82), Point(-46,-45), Point(-4,63), Point(16,-5), Point(4,1), Point(-3,-53), Point(0,-17), Point(9,98), Point(-18,26), Point(-9,86), Point(2,77), Point(-2,-49), Point(1,76), Point(-3,-38), Point(-8,7), Point(-17,-37), Point(5,72), Point(10,-37), Point(-4,-57), Point(-3,-53), Point(3,74), Point(-3,-11), Point(-8,7), Point(1,88), Point(-12,42), Point(1,-37), Point(2,77), Point(-6,77), Point(5,72), Point(-4,-57), Point(-18,-33), Point(-12,42), Point(-9,86), Point(2,77), Point(-8,77), Point(-3,77), Point(9,-42), Point(16,41), Point(-29,-37), Point(0,-41), Point(-21,18), Point(-27,-34), Point(0,77), Point(3,74), Point(-7,-69), Point(-21,18), Point(27,146), Point(-20,13), Point(21,130), Point(-6,-65), Point(14,-4), Point(0,3), Point(9,-5), Point(6,-29), Point(-2,73), Point(-1,-15), Point(1,76), Point(-4,77), Point(6,-29)}; 133 vector<Point> points(test,test+sizeof(test)/sizeof(Point)); 134 */ 135 /* 136 points.push_back(Point(2,2));// 137 points.push_back(Point(2,2));// 138 points.push_back(Point(2,2));// 139 */ 140 ///* 141 //测试用例:重复点问题,accept=4 142 points.push_back(Point(1,1));//0 143 points.push_back(Point(1,1));//1 144 points.push_back(Point(2,2));//2 145 points.push_back(Point(2,2));//3 146 //*/ 147 148 /* 149 //测试用例:输出应为6 150 points.push_back(Point(0,-12));//0 151 points.push_back(Point(5,2));//1 152 points.push_back(Point(2,5));//2 153 points.push_back(Point(0,-5));//3 154 points.push_back(Point(1,5));//4 155 points.push_back(Point(2,-2));//5 156 points.push_back(Point(5,-4));//6 157 points.push_back(Point(3,4));//7 158 points.push_back(Point(-2,4));//8 159 points.push_back(Point(-1,4));//9 160 points.push_back(Point(0,-5));//10 161 points.push_back(Point(0,-8));//11 162 points.push_back(Point(-2,-1));//12 163 points.push_back(Point(0,-11));//13 164 points.push_back(Point(0,-9));//14 165 */ 166 167 for(auto const &i : points) 168 cout << i.x << " "<<i.y<<endl; 169 cout << sol.maxPoints(points)<<endl; 170 return 0; 171 }
参考:
http://blog.csdn.net/linhuanmars/article/details/21060933
http://blog.csdn.net/doc_sgl/article/details/17103427