【每日刷题】直线上最多的点数

题目地址

https://leetcode-cn.com/problems/max-points-on-a-line/

题目描述: 直线上最多的点数

给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。

示例:

例 1:

输入: [[1,1],[2,2],[3,3]]

输出: 3

解释:

^
|
|        o
|     o
|  o  
+------------->
0  1  2  3  4

例 2:

输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]

输出: 4

解释:

^
|
|  o
|     o        o
|        o
|  o        o
+------------------->
0  1  2  3  4  5  6

解答

方法一:设置两个标记位,斜率 k 与截距 b, 然后统计二者对应的个数。

但是这种方法存在两个问题:

  1. 平行于 y 轴的点需要单独计算。
  2. 精度问题,若两点的坐标都非常大,且距离相近,则标记值无法很好的表示。
class Solution {
public:
    static bool cmp( vector<int> a, vector<int> b){
        if( a[0] != b[0])
            return a[0] < b[0];
        return a[1] < b[1];
    }
    
    int countVertical( vector<vector<int>>& points){    //统计竖直方向上最多的点
        int res = 1, count = 1;
        for( int i = 1; i < points.size(); i++)
            if( points[i-1][0] == points[i][0])
                count++;
            else
                res = max( count, res), count = 1;
        
        return max( count, res);
    }
    
    int maxPoints(vector<vector<int>>& points) {
        if( points.empty())  return points.size();
        //排序预处理
        sort( points.begin(), points.end(), cmp);
        
        int res = countVertical( points);
        
        map< pair<int,int>,int> rec;
        for( auto it:points)
            rec[{it[0], it[1]}]++;

        map< pair<long double,long double>, set<pair<int,int> > > record;  //第一个是pair,里面为斜率和映射到y轴上的点,第二个是该直线对应的点
        map< pair<long double,long double>, int > result;
        
        for( int i = 0; i < points.size(); i++)
            for( int j = i + 1; j < points.size(); j++)
                if( points[j][0] != points[i][0]){      //不在同一条垂直线上时
                    long double k = (points[j][1] - points[i][1]) * 1.0 / (points[j][0] - points[i][0]);
                    long double b = points[j][1] - k * points[j][0];
                    
                    if( record[{k,b}].find( {points[j][0], points[j][1]}) == record[{k,b}].end())
                        record[{k,b}].insert( {points[j][0], points[j][1]}), result[ {k,b}] += rec[ {points[j][0], points[j][1]}];
                    if( record[ {k, b}].find({ points[i][0], points[i][1]}) == record[{k,b}].end())
                        record[ {k, b}].insert({ points[i][0], points[i][1]}), result[ {k,b}] += rec[ {points[i][0], points[i][1]}];
                }  
                    
        //找出最多的个数
        for( auto it:result)
            if( res < it.second)
                res = it.second;
        
        return res;
    }
};

上述的方法虽然 AC, 但是时间和空间都不尽人意。

方法二:优化上述方法,可以将其约分程成最简形式来统计斜率。

方法三:斜率换一种形式。例如将分数转化为乘法。

你可能感兴趣的:(每日刷题)