在刷Leetcode的时候,第149题需要求经过两点的直线的表达式,所以总结一下如何用代码求出经过两点的直线的表达式

注:只考虑 x, y 为整数的情况,且不考虑计算中整型溢出的情况


求直线表达式需要解决的问题

1.求坐标系中经过两点的直线的表达式

表达式的形式为:y = a * x + b

根据两个点的坐标得到方程式:

①. y1 = a * x1 + b

②. y2 = a * x2 + b

得出 a 和 b 的表达式为(x1 - x2 不为 0 的情况下):

a = (y1 - y2)/(x1 - x2)

b = (x1 * y2 - x2 * y1)/(x1 - x2)

2.分数化简为真分数

由于 a, b 都可能为无限小数,且计算机存储浮点数存在精度问题,需要将 a, b 都用分数表示

若 a, b 不是真分数,那么同一条直线可能会有多条表达式,所以需要将 a, b 都化简为真分数

分数化简为真分数方法是:分子分母同时除以分子分母的最大公约数

3.求最大公约数

使用辗转相除法


求表达式相关代码

public class Util {private static final String ZERO = "0";/*** 求坐标系中经过两点的直线的表达式* <p>* 表达式的形式为:y = a * x + b* <p>* 根据两个点的坐标得到方程式:* ①. y1 = a * x1 + b* ②. y2 = a * x2 + b* <p>* 得出 a 和 b 的表达式为(x1 - x2 不为 0 的情况下):* a = (y1 - y2)/(x1 - x2)* b = (x1 * y2 - x2 * y1)/(x1 - x2)** @param point1 第一个点的坐标* @param point2 第二个点的坐标* @return 经过point1和point2的直线的表达式*/public static String getExpression(int[] point1, int[] point2) {if (point1.length != 2 || point2.length != 2) {throw new IllegalArgumentException("无效的点坐标");}if (point1[0] == point2[0] && point1[1] == point2[1]) {throw new IllegalArgumentException("两个点的坐标不能相同");}int x1 = point1[0];int y1 = point1[1];int x2 = point2[0];int y2 = point2[1];// 如果x1 == x2,无法套用公式,直接返回int denominator = x1 - x2;if (denominator == 0) {return "x = " + x1;}int numerator = y1 - y2;String a = fractionSimplification(denominator, numerator);numerator = x1 * y2 - x2 * y1;String b = fractionSimplification(denominator, numerator);String expression;if (ZERO.equals(a)) {expression = "y = " + b;} else if (ZERO.equals(b)) {expression = "y = " + a + " * x";} else {expression = "y = " + a + " * x + " + b;}return expression;}/*** 分数化简为真分数** @param denominator 分母* @param numerator   分子* @return 真分数 分子/分母*/public static String fractionSimplification(int denominator, int numerator) {if (denominator == 0) {throw new IllegalArgumentException("分母不能为0");}if (numerator == 0) {return ZERO;}String simpleFraction = new String();if (numerator % denominator == 0 && numerator / denominator != 0) {// 如果 分子/分母 为整数,相除的结果即为化简结果simpleFraction += numerator / denominator;} else {// 分数化简就是分母分子同时除以它们的最大公约数int gcd = gcd(denominator, numerator);simpleFraction = (numerator / gcd) + "/" + (denominator / gcd);}return simpleFraction;}/*** 求最小公倍数** @param a 第一个数* @param b 第二个数* @return 最小公倍数*/public static int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}public static void main(String[] args) {int[] a = {1, 1};int[] b = {1, 2};int[] c = {3, 2};int[] d = {1, 2};int[] e = {0, 0};int[] f = {1, 3};int[] g = {0, 1};int[] h = {1, 3};int[] i = {2, 4};int[] j = {5, 2};System.out.println(getExpression(a, b));System.out.println(getExpression(c, d));System.out.println(getExpression(e, f));System.out.println(getExpression(g, h));System.out.println(getExpression(i, j));}
}

解题

题目描述:

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

思路:

1.求出每两个点之间的直线表达式

2.统计每个表达式出现的次数,次数最多的表达式即为点最多的直线

3.根据表达式出现的次数求出点的个数:

n个点两两组合方式有 count = C(n, 2) = n!/(2! * (n-2)!) = (n² - n)/2 种
​
所以直线表达式的出现次数count与点的个数n之间的关系为: count = (n² - n)/2
​
解方程:
​
Δ = √(b² - 4ac) = √(1/4 + 2 * count)
n = 1/2 ± √(1/4 + 2 * count)
∵ count为非负整数
∴ min(Δ) = 1/2
∵ n > 0
∴ n = 1/2 + √(1/4 + 2 * count)

代码:

import java.util.HashMap;
import java.util.Map;class Solution {private static final String ZERO = "0";/*** 求坐标系中经过两点的直线的表达式* <p>* 表达式的形式为:y = a * x + b* <p>* 根据两个点的坐标得到方程式:* ①. y1 = a * x1 + b* ②. y2 = a * x2 + b* <p>* 得出 a 和 b 的表达式为(x1 - x2 不为 0 的情况下):* a = (y1 - y2)/(x1 - x2)* b = (x1 * y2 - x2 * y1)/(x1 - x2)** @param point1 第一个点的坐标* @param point2 第二个点的坐标* @return 经过point1和point2的直线的表达式*/public static String getExpression(int[] point1, int[] point2) {if (point1.length != 2 || point2.length != 2) {throw new IllegalArgumentException("无效的点坐标");}if (point1[0] == point2[0] && point1[1] == point2[1]) {throw new IllegalArgumentException("两个点的坐标不能相同");}int x1 = point1[0];int y1 = point1[1];int x2 = point2[0];int y2 = point2[1];// 如果x1 == x2,无法套用公式,直接返回int denominator = x1 - x2;if (denominator == 0) {return "x = " + x1;}int numerator = y1 - y2;String a = fractionSimplification(denominator, numerator);numerator = x1 * y2 - x2 * y1;String b = fractionSimplification(denominator, numerator);String expression;if (ZERO.equals(a)) {expression = "y = " + b;} else if (ZERO.equals(b)) {expression = "y = " + a + " * x";} else {expression = "y = " + a + " * x + " + b;}return expression;}/*** 分数化简为真分数** @param denominator 分母* @param numerator   分子* @return 真分数 分子/分母*/public static String fractionSimplification(int denominator, int numerator) {if (denominator == 0) {throw new IllegalArgumentException("分母不能为0");}if (numerator == 0) {return ZERO;}String simpleFraction = new String();if (numerator % denominator == 0 && numerator / denominator != 0) {// 如果 分子/分母 为整数,相除的结果即为化简结果simpleFraction += numerator / denominator;} else {// 分数化简就是分母分子同时除以它们的最大公约数int gcd = gcd(denominator, numerator);simpleFraction = (numerator / gcd) + "/" + (denominator / gcd);}return simpleFraction;}/*** 求最小公倍数** @param a 第一个数* @param b 第二个数* @return 最小公倍数*/public static int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}public static int maxPoints(int[][] points) {// 先获取每个点与其它任一点构成的直线表达式,并统计每个表达式的数量Map<String, Integer> expressionCountMap = new HashMap<>();for (int firstIndex = 0; firstIndex < points.length - 1; firstIndex++) {for (int secondIndex = firstIndex + 1; secondIndex < points.length; secondIndex++) {String expression = getExpression(points[firstIndex], points[secondIndex]);Integer count = expressionCountMap.get(expression);if (count == null) {expressionCountMap.put(expression, 1);} else {expressionCountMap.put(expression, count + 1);}}}// 出现次数最多的表达式即为点最多的直线的表达式int maxCount = 0;for (Map.Entry<String, Integer> entry : expressionCountMap.entrySet()) {if (entry.getValue() > maxCount) {maxCount = entry.getValue();}}// n个点两两组合方式有 C(n, 2) = n!/(2! * (n-2)!) = (n² - n)/2 种// 所以我们点最多的直线表达式的出现次数count与点的个数n之间的关系为: count = (n² - n)/2// 解方程:// Δ = √(b² - 4ac) = √(1/4 + 2 * count)// n = 1/2 ± √(1/4 + 2 * count)// ∵ count为非负整数// ∴ min(Δ) = 1/2// ∵ n > 0// ∴ n = 1/2 + √(1/4 + 2 * count)return (int) (0.5 + Math.sqrt((0.25 + 2 * maxCount)));}
}

求经过两点的直线的表达式(Leetcode.149)相关推荐

  1. [计算几何]知两点坐标求过两点的直线解析式

    我们设已知点为 A ( X 1 , Y 1 ) A(X_1,Y_1) A(X1​,Y1​), B ( X 2 , Y 2 ) B(X_2,Y_2) B(X2​,Y2​) 它们的 X X X坐标差为 X ...

  2. python 求平面两点距离_Python求平面内点到直线距离的实现

    近期遇到个问题,需要计算平面内点到直线的距离,发现数学知识都还给老师了,度娘后找到计算方法,特此记录. 点到直线的计算公式: 通过公式推导,得到信息: A:直线斜率 B:固定值-1 C:直线截距b 转 ...

  3. matlab已知三点求夹角,已知3点如何求其中两点对第3点的夹角

    公告: 为响应国家净网行动,部分内容已经删除,感谢读者理解. 话题:已知3点如何求其中两点对第3点的夹角? 问题详情:有3个问题:1)已知3点如何求其中两点对第3点的夹角?2)如何回答:1)已知3点求 ...

  4. 求圆心到点的直线与圆的相交点

    求圆心到点的直线与圆的相交点 点B为圆上一动点,已知圆心O(x2,y2), 圆外点A(x1,y1),圆半径r值,求B(x,y)坐标. 由图可知,产生下面两个公式. m/n = y1-y2/x1-x2 ...

  5. p点到(a,b)点两所在直线的垂点坐标及p点是否在(a,b)两点所在直线上

    /// <summary>         ///  p点到(a,b)点两所在直线的垂点坐标         /// </summary>         /// <pa ...

  6. AOJ GRL_1_C: All Pairs Shortest Path (Floyd-Warshall算法求任意两点间的最短路径)(Bellman-Ford算法判断负圈)

    题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_C All Pairs Shortest Path Input ...

  7. C#求空间两点之间的距离

    问题 求空间两点之间的距离 算法思想 d=sqrt(pow(x₁−x₂)+pow(y₁−y₂)+pow(z₁−z₂))d=sqrt(pow(x₁-x₂)+pow(y₁-y₂)+pow(z₁-z₂)) ...

  8. 使用Floyd-Warshall算法求出两点之间的最短路径

    求出下面任意两个点之间的最短路径: 如何才能求出两点之间的最短路径呢?大家都知道学几何的时候,有一条定理就是:两点之间线段最短.但是在实际情况中,我往往两点之间没有之间的通路而是一些曲折的线路. 上面 ...

  9. Dijkstra最短路由算法,求任意两点之间的最短距离【Java】

    一.问题 求下图中节点0到节点5之间的最短距离 二.方法 Dijkstra最短路由算法.本文不再赘述,直接上代码,如果不懂,可以参考 文章 三.代码 public class MyDijkstra { ...

最新文章

  1. CVPR2020 | 通过可微的代理投票损失进行6DoF对象位姿估计
  2. JAVA入门到精通-第71讲-学生管理系统3-增删改查
  3. 成功解决AttributeError: module ‘seaborn‘ has no attribute ‘lvplot‘
  4. spring cloud feign 加载流程
  5. 让思考成为一种习惯:一位软件工程专业学生的大学生涯规划
  6. java5年转c语言,时隔5年,C语言再次领先Java,荣登编程语言排行榜第一!
  7. SpringBoot笔记(二)
  8. 使用HTML5实现刮刮卡效果
  9. 前端学习(2009)vue之电商管理系统电商系统之渲染商品属性的结构
  10. ucc编译器(语法解析)
  11. 软件工程师如何应对面试的可怕“反乌托邦世界”?
  12. 2021牛客暑期多校训练营5,签到题BDHJK
  13. 【美团外卖】美食知识图谱的迭代及应用
  14. linux 内存坏了,Linux的缓存内存 Cache Memory详解
  15. android+显示ui布局,[Android ]UI布局 (线性布局+相对布局)
  16. 十大免费java开源商城系统
  17. [线性代数]向量2-范数三角不等式证明
  18. 【总结】1361- package.json 与 package-lock.json 的关系
  19. 清华大学鲍橒计算机1999,鲍橒从“最强大脑”到“盲棋第一人”
  20. C语言手机通讯录系统

热门文章

  1. 设置echarts雷达图label标签出现的位置聚拢或发散
  2. (74)Verilog实现CRC【MIPI】
  3. 安东尼罗宾--激发你的无限潜能[连载]--1 2章
  4. 给新手学习MySQL的建议
  5. OpenGL: 基础篇
  6. python所用到的英语单词_用python从字符串中提取英语单词
  7. 2016网络大事记 mark
  8. 笔记本电脑打开后不显示桌面_70后、80后、90后、00后……不一样的夏天打开方式,满满回忆!| 特别关注...
  9. matlab ob,Matlab 飞机航向INS仿真
  10. ai人工智能相关职业_2020年及以后的5个人工智能最佳职业