平面最近点对问题求解—基于Java语言

1. 问题描述:

本问题来自《编程之美2.11—寻找最近点对》,文中给出了两种解法:暴力解法,分治解法。其中,暴力解法很简单,求出所有点之间的距离并做比较,便可找到距离最小的点对;当然,这不是最优解,时间复杂度为O(n^2)。文中还介绍了分治法,不过,没有给出源代码,网上的解法也多是基于C写的,本文将基于Java用分治法解决这个问题。

2.分治法解法思想

分治法思路: 
1) 把它分成两个或多个更小的问题; 
2) 分别解决每个小问题; 
3) 把各小问题的解答组合起来,即可得到原问题的解答。小问题通常与原问题相似,可以递归地使用分而治之策略来解决。

这里的分治算法的主要思路是将平面上的n个点分为两个子集S1,S2。每个子集中有n/2个点,然后递归的在每个子集中求解最近点对,两边求得的结果如图所示:

那么可以看出左边的最近点对的距离为d1,右边为d2。但是最近对可能一个点在S1中而另一个点在S2中。这样,我们,就要去想办法对其进行合并,然后求得合并区域的最近对距离,假设为d3,那么只需要比较d1,d2,d3的大小关系即可,最小的就是平面最近对的距离。通过分析我们可以知道,如果存在这样的最近对的点,那么这个点在S1集合中,肯定是横坐标最靠近中位线 L 的点,S2中同理。那么这个范围如何划定呢?


d=min(d1,d2)假定中位线横坐标为X,那么范围就是[X-d,X+d].这个范围是怎么划定的呢?根据平面中点的位置我们就可以知道,两点的距离为横纵坐标之间的差值的平方和。那么如果要存在这样的点,他们之间的横坐标之间的差值的绝对值必须要小于等于d(这里包括这点恰好就在中位线 L 上)。这样可以筛选出横坐标为[X-d,X+d]的区域。如下图所示:


可以看出这个区域中包含三个点,只需要求出这三个点之间的最近点对即可(蛮力法)。这里还需要注意一点,上面是通过横坐标筛选的这个区域,这里可以根据纵坐标将纵坐标差的绝对值大于 d 的坐标剔除。

3. 基于分治法的解法代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;public class MinDis
{public static void main(String[] args){// 测试用例Point[] points = new Point[7];points[0] = new Point(1, 1);points[1] = new Point(1, 9);points[2] = new Point(2, 5);points[3] = new Point(3, 1);points[4] = new Point(4, 4);points[5] = new Point(5, 8);points[6] = new Point(6, 2);// 预处理,基于x轴坐标排序,便于分治法实施Arrays.sort(points, new Comparator<Point>(){@Overridepublic int compare(Point p1, Point p2){return (p1.x > p2.x) ? 1 : (p1.x == p2.x) ? 0 : -1;}});// 测试System.out.println(divide(0, points.length-1, points));}/*** 求平面上距离最近的两个点* */public static double divide(int left, int right, Point[] points){// 当前最小两点距离,初始值设置为无穷大double curMinDis = 1e20;// 如果只有一个点,则不存在最近两点距离,返回无穷大if (left == right){return curMinDis;}// 这里是判断是否为只有两个点,如果只有两个点的话那么直接求解。if (left + 1 == right){return distance(points[left], points[right]);}// 分治法:第一步:分区,并求取左右分区最小两点距离// 通过右移运算除2,对区域进行合理的划分,使得左右两边保持大致相等个数点int middle = (left + right) >> 1;double leftMinDis = divide(left, middle, points);double rightMinDis = divide(middle, right, points);curMinDis = (leftMinDis <= rightMinDis) ? leftMinDis : rightMinDis;// 分治法:第二步:假设距离最近的两点分别在左右分区中// 关键代码,距离最近的两个点,一个位于左边区域,一个位于右边区域,x轴搜索范围[middle-curMinDis, middle+curMinDis]// 记录搜索区间内的点的索引,便于进一步计算最小距离List<Integer> validPointIndex = new ArrayList<>();for (int i = left; i <= right; i++){if (Math.abs(points[middle].x - points[i].x) <= curMinDis){validPointIndex.add(i);}}// 基于索引,进一步计算区间内最小两点距离for (int i = 0; i < validPointIndex.size() - 1; i++){for (int j = i + 1; j < validPointIndex.size(); j++){// 如果区间内的两点y轴距离大于curMinDis,则没必要计算了,因为,它们的距离肯定大于curMinDis,if (Math.abs(points[validPointIndex.get(i)].y- points[validPointIndex.get(j)].y) > curMinDis){continue;}double tempDis = distance(points[validPointIndex.get(i)],points[validPointIndex.get(j)]);curMinDis = (tempDis < curMinDis) ? tempDis : curMinDis;}}return curMinDis;}/*** 计算两点间的距离*/public static double distance(Point p1, Point p2){return Math.sqrt((p2.y - p1.y) * (p2.y - p1.y) + (p2.x - p1.x) * (p2.x - p1.x));}
}
/*** 定义点* */
class Point
{public int x;public int y;Point(int x, int y){this.x = x;this.y = y;}
}

特别说明:

本文部分内容摘录自博客:https://blog.csdn.net/Up_junior/article/details/52019943

平面最近点对问题求解—基于Java语言相关推荐

  1. Leetcode刷题第1题:两数之和(基于Java语言)

    ** Leetcode刷题第1题:两数之和(基于Java语言) ** 题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标 ...

  2. Leetcode刷题 463题:岛屿的周长(基于Java语言)

    ** Leetcode刷题 463题:岛屿的周长(基于Java语言) ** 一. 题目描述: 给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域. 网格中的格子水平和垂直方向相 ...

  3. 基于Java语言构建区块链(一)—— 基本原型

    最终内容请以原文为准:https://wangwei.one/posts/df1... 引言 区块链技术是一项比人工智能更具革命性的技术,人工智能只是提高了人类的生产力,而区块链则将改变人类社会的生产 ...

  4. java 计算移动平均线_基于Java语言开发的个性化股票分析技术:移动平均线(MA)...

    基于Java语言开发的个性化股票分析技术:移动平均线(MA) 基于 Java 语言开发的个性化股票分析技术:移动平均线(MA)移动平均线(MA)是以道·琼斯的"平均成本概念"为理论 ...

  5. 基于Java语言构建区块链(四)—— 交易(UTXO)

    基于Java语言构建区块链(四)-- 交易(UTXO) 2018年03月11日 00:48:01 wangwei_hz 阅读数:909 标签: 区块链比特币 更多 个人分类: 区块链 文章的主要思想和 ...

  6. 基于Java语言构建区块链(五)—— 地址(钱包)

    基于Java语言构建区块链(五)-- 地址(钱包) 2018年03月25日 18:02:06 wangwei_hz 阅读数:1292更多 个人分类: 区块链bitcoin比特币 文章的主要思想和内容均 ...

  7. 基于Java语言构建区块链(六)—— 交易(Merkle Tree)

    基于Java语言构建区块链(六)-- 交易(Merkle Tree) 2018年04月16日 10:21:35 wangwei_hz 阅读数:480更多 个人分类: 区块链比特币bitcoin 最终内 ...

  8. 基于java语言轻量级实时风控引擎

    介绍: radar是一款基于java语言,使用Springboot + Mongodb + Groovy + Es等框架搭建的轻量级实时风控引擎,适用于反欺诈应用场景,极简的配置,真正做到了开箱即用. ...

  9. java 解析数据包_一种基于Java语言的网络通讯数据包解析方法与流程

    本发明涉及网络通讯领域,特别涉及一种基于Java语言的网络通讯数据包解析方法. 背景技术: 计算机系统和网络的大量普及使用使全球跨入了信息化时代.但是,正由于现代社会中几乎一切都在"计算机化 ...

最新文章

  1. TextView显示插入的图片
  2. oracle 数据库的非指令备份方法
  3. [代码示例]用Fine Uploader+ASP.NET MVC实现ajax文件上传
  4. 【最新合集】编译原理习题(含答案)_11-14中间代码生成_MOOC慕课 哈工大陈鄞
  5. Thinkpad X240使用U盘安装Win7系统
  6. java面试题6 牛客:哪个关键字可以对对象加互斥锁?
  7. 《北大学科》第一季:数学篇
  8. [机器学习-坑] error: Microsoft Visual C++ 14.0 is required
  9. PyTorch 1.0 中文文档:Torch 脚本
  10. Mycat安全_监控平台简介---MyCat分布式数据库集群架构工作笔记0035
  11. 激情转型 三大战役重塑AMD
  12. [C/C++] ccpuid:CPUID信息模块 V1.02版,支持Mac OS X,支持纯C,增加CPUF常数
  13. 荣耀盒子刷鸿蒙,华为荣耀盒子ROOT 刷机大师刷荣耀盒子
  14. 转:FAMI上的满分游戏
  15. 数学分析教程 第十八章学习感受
  16. 自动驾驶领域中常见英文缩写、相关含义以及常用专业英文
  17. PhotoShop十大使用技巧总结
  18. Java使用Lambda表达式多字段求和
  19. Fleck实现简单的Websocket
  20. Batch Size 对训练的影响

热门文章

  1. mysql中生成字符串对应的英文字母(拼音首字母)
  2. 在linux下使用debugfs恢复rm删除的文件
  3. 4星|《维米尔的帽子》:17世纪荷兰画中的全球化踪迹,鸦片与烟草被当时中国主流文化接纳的故事...
  4. qbo_arduqob command 命令Id约定
  5. sa-token进阶
  6. 词云和穷爸爸、富爸爸
  7. 用Python读取照片拍摄的详细信息(拍摄时间、地址等)
  8. NBOJv2 Problem 1009 蛤玮的魔法(二分)
  9. 模糊控制器隶属度函数绘制
  10. 18岁以后,大学生长高个子的秘诀是什么?