题目原链接:
https://leetcode.com/problems/max-points-on-a-line/description/
Difficulty:Hard
Total Accepted:100.8K
Total Submissions:661.4K
题目需要求出在同一条直线的最大点数。
咋一看比较简单,于是就直接拿斜率来求解,斜率一样的也就是在一条直线上。
但很快开始暴露出问题,
- 一是可能有不同的点位置重合
- 二是斜率的精度应该要用何种方法存储,因为如果用浮点数存储,那么会有精度问题,特别是当点的横坐标和纵坐标比较大的时候,会出现精度误差,从而影响运算结果。
- 第三点需要考虑的是数据存储结构,例如我一开始用struct+vector的方式存储,但在查找相同斜率的点时需要o(n)的复杂度,明显不如map的直接映射效率高。
//原来的数据结构
struct Slope {
float slope;
int times;
Slope(float s,int t) :slope(s), times(t) {}
};
因此针对上面的三点,分别作出的该进如下:
- 将重合的点用map< pair< int, int>, int> pointsMap来去重
- 对于斜率精度问题,用string来存储被除数和除数,在存储之前先同时除以最大公约数化简。
- 对于数据存储结构,利用map < string, int > 的结构代替struct slope+ vector < slope >
//原来的代码
class Solution {
struct Slope {
float slope;
int times;
Slope(float s,int t) :slope(s), times(t) {}
};
float slopeTemp;
vector<Slope> SlopeVec;
int samepoint;
bool isPush;
public:
int maxPoints(vector<Point>& points) {//还有[] 的输入
Slope ss(LONG_MAX,0);//用来存储横坐标相等的
SlopeVec.push_back(ss);
if (points.size() == 0) {
return 0;
}
for (int i = 0; i < points.size(); i++) {
samepoint = 0;
for (int j = i+1; j < points.size(); j++) {
isPush = false;
if (points[i].x == points[j].x &&points[i].y == points[j].y) {
samepoint++;
}
else if (points[i].x == points[j].x) {
SlopeVec[0].times++;
break;
}
slopeTemp = (float)(points[i].y - points[j].y) / (float)(points[i].x - points[j].x);
for (int x = 1; x < SlopeVec.size(); x++) {//第零位用来存横坐标相等的
if ( fabs(slopeTemp-SlopeVec[x].slope)<1e-6 ) {
SlopeVec[x].times++;
isPush = true;
}
}
if (!isPush) {
Slope slope(slopeTemp, 1);
SlopeVec.push_back(slope);
}
}
}
int maxTimes = 0;
for (int i = 0; i < SlopeVec.size(); i++) {
if (SlopeVec[i].times > maxTimes) {
maxTimes = SlopeVec[i].times;
}
}
int result = 1;
while (maxTimes != 1) {
maxTimes = maxTimes - result;
result++;
}
return result;
}
};
下面是最终的通过代码,但效率还不够高,但理解较方便,先用map去重,再用记录斜率的map来存储同个斜率上的点数。
class Solution {
map<pair<int, int>, int> pointsMap;
int samepoint;
int sameX;
int result, resultTemp;
int xLength, yLength, g;
public:
/* 迭代法(递推法):欧几里得算法,计算最大公约数 */
int gcd(int m, int n) {
while (m>0) {
int c = n % m;
n = m;
m = c;
}
return n;
}
int maxPoints(vector<Point>& points) {//还有[] 的输入
result = 0;
if (points.size() == 0) {
return 0;
}
for (int i = 0; i < points.size(); i++) {
pair<int, int> pairTemp(points[i].x, points[i].y);
pointsMap[pairTemp]++;
}
for (auto i = pointsMap.begin(); i != pointsMap.end(); i++) {
sameX = 0;
resultTemp = 0;
map<string, int> slopeMap;
for (auto j = i; j != pointsMap.end(); j++) {
if (i == j) {
continue;
}
if (i->first.first == j->first.first) {//points[i].x == points[j].x
pair<int, int> temp(j->first.first, j->first.second);
sameX += pointsMap[temp];
}
else {
xLength = i->first.first - j->first.first;
yLength = i->first.second - j->first.second;//points[i].y - points[j].y;
g = gcd(abs(xLength), abs(yLength));//第一个系数不能为0
xLength /= g;
yLength /= g;
if (yLength < 0) {//确保y长度为正数
yLength *= -1;
xLength *= -1;
}
stringstream ss;
ss << xLength << "," << yLength;
string slopeStr(ss.str());
pair<int, int> temp(j->first.first, j->first.second);
slopeMap[slopeStr] += pointsMap[temp];
resultTemp = max(resultTemp, slopeMap[slopeStr]);//找到相同斜率下最多点的那个斜率
}
}
resultTemp = max(resultTemp, sameX);//找出与此点同列的点数比较
pair<int, int> temp(i->first.first, i->first.second);
result = max(result, resultTemp + pointsMap[temp]);
}
return result;
}
};