Best Line:给定平面上n
个点,找出一条直线,使其通过的点数最多。
书上的解法:求出两两相连后的斜率,平行线归为一类,在平行线中找重合的直线。由于存在浮点数误差,斜率差值小于epsilon
的也算做平行线。
由于力扣上的输入都是整数,所以不用考虑epslion
的问题。要求返回序号最小的两个点,所以对于同一斜率的平行线,只统计在它后面被添加的平行线上的点就可以了,但是要注意判重。根据这两点调整了一下书上的写法,不过超时了。
class Solution {
int nPoint;
static bool equal(const double d1, const double d2)
{
return abs(d1 - d2) <= 1e-6;
}
struct Line
{
double slope, intercept;
bool bVertical;
int i, j;
Line(const vector<int> &p1, const vector<int> &p2, const int idx1, const int idx2) : i(idx1), j(idx2)
{
if(Solution::equal((double)p1[0], (double)p2[0])){
bVertical = true;
slope = 0.0;
intercept = p1[0];
}
else{
bVertical = false;
slope = 1.0 * (p1[1] - p2[1]) / (p1[0] - p2[0]);
intercept = p1[1] - slope * p1[0];
}
}
};
int countSameSlope(const size_t k, const vector<Line> &lines)
{
int cnt = 2;
vector<bool> vbPoint(nPoint, false);
vbPoint[lines[k].i] = true, vbPoint[lines[k].j] = true;
for(size_t i = k + 1; i < lines.size(); i++)
{
if((lines[k].bVertical && lines[i].bVertical && Solution::equal(lines[k].intercept, lines[i].intercept)) ||
(Solution::equal(lines[k].slope, lines[i].slope) && Solution::equal(lines[k].intercept, lines[i].intercept))){
cnt += (vbPoint[lines[i].i] ? 0 : 1) + (vbPoint[lines[i].j] ? 0 : 1);
vbPoint[lines[i].i] = true, vbPoint[lines[i].j] = true;
}
}
return cnt;
}
public:
vector<int> bestLine(vector<vector<int>>& points) {
nPoint = points.size();
map<double, vector<Line>> mSlope2Line;
vector<Line> VertLine;
vector<int> S(2, nPoint);
int maxCnt = 0;
for(size_t i = 0; i < points.size(); i++)
{
for(size_t j = i + 1; j < points.size(); j++)
{
Line line(points[i], points[j], i, j);
if(!line.bVertical){
mSlope2Line[line.slope].push_back(line);
}
else{
VertLine.push_back(line);
}
}
}
for(auto iter = mSlope2Line.begin(); iter != mSlope2Line.end(); iter++)
{
const vector<Line> &lines = iter->second;
for(size_t k = 0; k < lines.size(); k++)
{
vector<int> s({lines[k].i, lines[k].j});
int cnt = countSameSlope(k, lines);
if(cnt > maxCnt){
maxCnt = cnt;
S = s;
}
}
}
for(size_t k = 0; k < VertLine.size(); k++)
{
vector<int> s({VertLine[k].i, VertLine[k].j});
int cnt = countSameSlope(k, VertLine);
if(cnt > maxCnt){
maxCnt = cnt;
S = s;
}
}
return S;
}
};
超时的原因可能是执行了两次循环,看起来时间复杂度在同一量级应该不影响,但是执行两次,时间还是会多一倍,如果把两个循环合并为一个,或许可以减少点时间。所以直接枚举所有可能的直线,再逐个判定序号更大的点是否在直线上即可。
class Solution {
static bool equal(const double d1, const double d2)
{
return abs(d1 - d2) <= 1e-6;
}
struct Line
{
double slope, intercept;
bool bVertical;
Line(const vector<int> &p1, const vector<int> &p2)
{
if(Solution::equal((double)p1[0], (double)p2[0])){
bVertical = true;
slope = 0.0;
intercept = p1[0];
}
else{
bVertical = false;
slope = 1.0 * (p1[1] - p2[1]) / (p1[0] - p2[0]);
intercept = p1[1] - slope * p1[0];
}
}
};
public:
vector<int> bestLine(vector<vector<int>>& points) {
int maxCnt = 0;
int l1 = 0, l2 = 1;
for(size_t i = 0; i < points.size(); i++)
{
for(size_t j = i + 1; j < points.size(); j++)
{
int cnt = 2;
Line line(points[i], points[j]);
for(size_t k = j + 1; k < points.size(); k++)
{
if(!line.bVertical){
if(Solution::equal(line.slope * points[k][0] + line.intercept, (double)points[k][1])){
cnt++;
}
}
else{
if(Solution::equal(line.intercept, (double)points[k][0])){
cnt++;
}
}
}
if(cnt > maxCnt){
maxCnt = cnt;
l1 = i, l2 = j;
}
}
}
return vector<int>{l1, l2};
}
};