「前端刷题」149.直线上最多的点数(HARD)

113 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

链接:https://leetcode-cn.com/problems/max-points-on-a-line
解决数:645
通过率:37.1%
标签:几何 数组 哈希表 数学 
相关公司:linkedin google amazon 

给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。

 

示例 1:

输入: points = [[1,1],[2,2],[3,3]]
输出: 3

示例 2:

输入: points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4

 

提示:

  • 1 <= points.length <= 300
  • points[i].length == 2
  • -104 <= xi, yi <= 104
  • points 中的所有点 互不相同

思路

算法实现:

  • 利用斜率公式 k=(y2y1)/(x1x2)k = (y₂-y₁)/(x₁-x₂) 判断是否在一条直线上,以 kkkeykey 存储到 MapMap 结构中,遇到相等的 kk 则使 value+1value+1
  • kk 存在时至少有两点在一条直线上,所以 [key:k,value:2][key:k,value:2]valuevalue 的初始值为 22;或者初始值为 11,最后求最大值时 value+1value+1
  • 因为题目条件 1<=points.length<=3001 <= points.length <= 300,所以最少 11 个点在直线上
/**
 * @param {number[][]} points
 * @return {number}
 */
var maxPoints = function(points) {
    let max = 1;
    for(let i = 0; i < points.length; i++){
        let map = new Map();
        for(let j = 0; j < points.length; j++){
            if(i === j) continue
            let k = (points[i][1] - points[j][1]) / (points[i][0] - points[j][0])
            map.set(k, map.has(k) ? map.get(k) + 1 : 2);
        }
        for(let val of map.values()){
            max = Math.max(max, val);
        }
    }
    return max;
};
function maxPoints(points: number[][]): number {
    let max = 1;
    for(let i = 0; i < points.length; i++){
        let map = new Map();
        for(let j = 0; j < points.length; j++){
            if(i === j) continue
            let k = (points[i][1] - points[j][1]) / (points[i][0] - points[j][0])
            map.set(k, map.has(k) ? map.get(k) + 1 : 2);
        }
        for(let val of map.values()){
            max = Math.max(max, val);
        }
    }
    return max;
};

复杂度分析

  • 时间复杂度:O(n2)O(n²)
  • 空间复杂度:O(n)O(n)

思路2

  • 思路:遍历所有点,针对每个点,固定该点,找其他点与该点组成的直线,记录斜率

  • 注意事项:

    • 记录斜率的Hash不能为空,否则在 Math.max(...Object.values(hash)) 时会为 -Infinity
    • 斜率为 +-Infinity 时,即为无斜率直线,应该记录在同一个 key 下
    • 题目没说,但同一个点出现多次,也是要计数的

代码

/**
 * @param {number[][]} points
 * @return {number}
 */
const maxPoints = (points) => {
  if (points.length <= 2) return points.length
  let result = 2, n = points.length
  for (let i = 0; i < n-1; i++) {
    let hash = {_: 0}, dup = 1
    for (let j = i+1; j < n; j++) {
      let [[x1, y1], [x2, y2]] = [points[i], points[j]]
      if (x1 === x2 && y1 === y2) { dup++; continue }
      let k = (x1-x2) / (y1-y2)
      if (k === -Infinity) k = Infinity
      hash[k] = hash[k] ? hash[k] + 1 : 1
    }
    result = Math.max(result, Math.max(...Object.values(hash))+dup)
  }
  return result
};