数据结构问题集锦 - Max Points on a Line问题

别看这个问题的名字非常高大上,其实说的问题非常浅显易懂,就是在一个给定平面上有很多个点(给出的是它们的坐标),求出公共点最多的一条直线。(这回的开头还是直入主题吧,毕竟在大作业的面前已经焦头烂额了)

最简单的一种方法就是,每两个点作一条直线,然后遍历所有点,统计在当前直线上的点的个数:

 1 class Solution {
 2 public:
 3     int maxPoints(vector<Point>& points)
 4     {   unsigned int i, j, k;
 5         unsigned int result = 0;
 6
 7         if (points.size()==1)
 8             return 1;
 9
10         for (i=0;i<points.size();i++)
11             for (j=i+1;j<points.size();j++)
12             {   unsigned int count = 0;
13
14                 if (points[i].x==points[j].x)
15                 {   unsigned int x = points[i].x;
16
17                     for (k=0;k<points.size();k++)
18                         if (points[k].x==x)
19                             count++;
20                 }
21                 else
22                 {   double x1 = points[i].x, x2 = points[j].x,
23                         y1 = points[i].y, y2 = points[j].y;
24                     double l_k = (y2-y1)/(x2-x1), l_b = y1-x1*l_k;
25
26                     for (k=0;k<points.size();k++)
27                         if (round(l_k*points[k].x+l_b)==points[k].y)
28                             count++;
29                 }
30
31                 if (count>result)
32                     result = count;
33             }
34
35         return result;
36     }
37 };

在这个算法中,每两个点确定一条直线,对应于i与j构成的循环。对每一直线遍历所有点,对应k构成的循环。这样该算法的复杂度为O(n^3)。(不过令人惊讶的是Leetcode上居然没有发生超时的情况,确实令我感到意外。不过怨念的是似乎最后一个测试样例总是有问题,不知是什么样的原因)

当然,上面这个算法的效率实际上是不高的。我们注意到,如果平面上的n个点都共线的话,那么任取两点,所得直线的斜率与截距都应当一样,于是就可以写出下面的代码:

struct line
{
	bool vertical;
	double b;
	double k;

	bool operator ==(const line& another) const
	{
		return (this->vertical == another.vertical) && (this->b == another.b) && (this->k == another.k);
	}
};

namespace std
{
	template <>
	struct hash<line>
	{
		size_t operator()(const line& l) const
		{
			return (hash<bool>()(l.vertical)) ^ (hash<double>()(l.k)) ^ (hash<double>()(l.b));
		}
	};

	template <>
	struct hash<pair<int, int>>
	{
		size_t operator()(const pair<int, int>& p) const
		{
			return (hash<int>()(p.first)) ^ (hash<int>()(p.second));
		}
	};
}

class Solution {
public:
	int maxPoints(vector<Point>& points)
	{
		unsigned int i, j;
		unordered_map<line, unordered_set<pair<int, int>>> result;

		for (i = 0; i<points.size(); i++)
			for (j = i + 1; j<points.size(); j++)
			{
				double x1 = points[i].x, x2 = points[j].x,
					y1 = points[i].y, y2 = points[j].y;
				line current_line;

				if (x1 == x2)
					current_line = { true, x1, 0 };
				else
				{
					double k = (y2 - y1) / (x2 - x1);
					current_line = { false, y1 - x1*k, k };
				}

				auto ptr = result.find(current_line);
				if (ptr == result.end())
					result[current_line] = unordered_set<pair<int, int>>();
				result[current_line].insert(pair<int, int>(points[i].x, points[i].y));
				result[current_line].insert(pair<int, int>(points[j].x, points[j].y));
			}

		auto ptr = result.begin();
		unsigned int max_points = 0;
		while (ptr != result.end())
		{
			if (ptr->second.size() > max_points)
				max_points = ptr->second.size();
			ptr++;
		}

		return max_points;
	}
};

(这段代码Leetcode居然不能编译,然而放到VS上却毫无问题能够正常运行,百思不得其解,今天本人的人品也是差到了极点...也或许是因为GCC和VS的STL的差别吧)

分析复杂度可知,对任两点算截距于斜率并添加到Map中,复杂度为O(n^2),之后遍历Map的过程复杂度为O(n),所以可以认为整个过程的复杂度为O(n^2),相对来说该算法的优化程度是比较高的。(这里用到的Map与Set是unordered_map与unordered_set,它们的实现方式可以简单认为是根据Hash把Value或者Key-Value Pair放入固定个数的Bucket中,如果装填因子过小或者过大就令Bucket个数折半或者翻倍,已有Bucket中Hash进行重分配。在理想情况下,插入与删除的复杂度均为O(1),遍历时间复杂度则与Bucket个数相关,但是一般装填因子都控制在一定范围内,所以可以认为Bucket数与存储数据量成正比,故复杂度为O(n))

如果使用hash_map与hash_set的话,由于hash_map与hash_set都使用平衡树,增加与删除元素复杂度均为O(n),遍历复杂度为O(nlogn),所以整个算法的复杂度会变为O(n^2logn)(实际上,hash_map与hash_set是针对存入数据需要排序的情况而设计的,但是此题中的数据不需要考虑顺序问题所以应当选择无序集合与映射。这启示我们针对不同的问题要根据需求决定采用的数据结构,这样才能最为高效地解决问题)

时间: 2024-08-07 00:26:15

数据结构问题集锦 - Max Points on a Line问题的相关文章

Max Points on a Line leetcode java

题目: Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. 题解: 这道题就是给你一个2D平面,然后给你的数据结构是由横纵坐标表示的点,然后看哪条直线上的点最多. (1)两点确定一条直线 (2)斜率相同的点落在一条直线上 (3)坐标相同的两个不同的点 算作2个点 利用HashMap,Key值存斜率,Value存此斜率下的点的个数.同时考虑特殊情况,如

【leetcode】Max Points on a Line (python)

给定一个点,除该点之外的其他所有点中,与该点的关系要么是共线,要么就是共点,也就是两点重合. 共线有三种情况:水平共线,垂直共线,倾斜的共线.合并下这三种情况就是斜率存在的共线和斜率不存在的共线. 那么我们的任务就是针对每个点,找出与其共线的这些情况中,共线最多的点的个数. 注意:最终的结果别忘了加上共点的个数. class Solution: def maxPoints(self, points ): if len( points ) <= 1: return len( points ) ma

【leetcode刷题笔记】Max Points on a Line

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. 题解: 思路比较简单,每条直线都可以表示为y=kx+b,所以对于任意三点,如果它们共线,那么它们中任意两点的斜率都相等. 所以就遍历points数组,对其中的每一个元素计算它和位于它后面的数组元素的斜率并保存在一个hashmap中. 这个hashmap的键就是两点构成直线的斜率,值就是和当前元素po

[LeetCode][JavaScript]Max Points on a Line

Max Points on a Line Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. 求有多少点在一直线上. 粗暴地用二重循环遍历. 每一轮都构造一个哈希表,用来记录斜率,斜率k = (y1 - y2) / (x1 - x2). 注意到特殊情况: 1.两点重合,用countSamePoint记下重复的点,最后加到结果上. 2.两点与X轴平行,

LeetCode:Max Points on a line

题目:Max Points on a line Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. 这道题需要稍微转变一下思路,用斜率来实现,试想找在同一条直线上的点,怎么判断在一条直线上,唯一的方式也只有斜率可以完成,我开始没想到,后来看网友的思路才想到的,下面是简单的实现:其中有一点小技巧,利用map<double, int>来存储具有相同斜率

[LeetCode OJ] Max Points on a Line—Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

//定义二维平面上的点struct Point { int x; int y; Point(int a=0, int b=0):x(a),y(b){} }; bool operator==(const Point& left, const Point& right) { return (left.x==right.x && left.y==right.y); } //求两个点连接成的直线所对应的斜率 double line_equation(const Point&

LeetCode: Max Points on a Line 解题报告

Max Points on a Line Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. SOLUTION 1: 全部的点扫一次,然后计算每一个点与其它点之间的斜率. 创建一个MAP, KEY-VALUE是 斜率:线上的点的数目. 另外,注意重合的点,每次都要累加到每一条线上. 注意: 1. k = 0 + (double)(points[i].

[leetcode]Max Points on a Line @ Python

原题地址:https://oj.leetcode.com/problems/max-points-on-a-line/ 题意:Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. 解题思路:找到平面上在一条直线上最多的点.点在同一条直线上意味着这些点的斜率是一样的,那么可以考虑使用哈希表来解决,{斜率:[点1,点2]}这样的映射关系.这里有几个需要考虑

LeetCode OJ - Max Points on a Line

题目: Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. 解题思路: 第一反应:枚举两个点组成的直线,然后看其他的点在不在这条直线上,在此过程中统计最大值.此思路的复杂度 O(n^3) 参考了网上的思路:枚举第一个点,用unordered_map来记录其余的点和这个点的斜率,若斜率相同则代表这些点在同一直线上.避免double问题,把斜率转化成化简