给定数轴上的n个点,求距离最近的两个点的距离

public class MinimumSpacing {
    //给定平面上的n个点,求距离最近的两个点的距离。
    //无从下手的话,先分解问题,分解成简单的,逐个分析,然后再合在一起考虑
    //这是个2维的数据,那就先降维到1维分析
    //先考虑在一条数轴上有n个点,求最近距离的2个点的距离
    //
    // ------*--*------*---*--->
    //用分治思想处理
    // 1.分割 2.处理 3.合并 3个步骤
    //
    // 1.分割:
    // 将整个数据[先排序]得到数组s,然后将s从中间一份为二(分割点m下标为, m=(l+r)/2) ,(最小下标+最大下标) / 2,得到左半边s1,和右半边s2
    // ------*--*---|---*---*--->
    //       l      m       r
    //         s1        s2
    //              s
    // 当点的个数n有基数个时,左半边为 s1=s[l,m] ,右半边 为 s2=s(m,r]
    // 例如n=3   l=0 ,r=2   m=2/2 = 1    ,s1 = 0,1 (2个元素)  .s2=2 (1个元素) , s1比s2多一个元素
    // n为偶数时候 = 4
    // m = 0+3/2 = 1 , s1=0,1   s2=2,3  ,s1和s2元素一样多
    //
    // 2.处理:
    // 用递归的方式处理左右两边,先考虑最小情况
    // n = 0 和 n = 1 时
    // 返回 -1 ,代表无法判断2个最近的点是哪两个,因为点的个数不足2个
    // n = 2 时
    // 直接返回 2个点的距离=d
    // n = 3 时
    // 此时不是最小情况,需要继续切分成2份,分治处理,按照1.分割 的方式去分割
    //
    // 3.合并:
    // 从非最小情况开始考虑(n>=3)
    // 因为将s这个数组分割成了2份,每一份会返回该区域的最短距离值(除非不存在,则返回-1,代表该区域只分得0个或1个点,无法判断最小距离)
    // ds1 代表 左侧 这一半返回的最小距离
    // ds2 代表 右侧 这一半返回的最小距离
    // ds 代表当前这个数组应返回的最小距离
    // n=3时
    //         ds
    //        dsgap (处于分割线两段的点的距离)
    //    ds1   (ds2:不存在)
    // ---*---*|---*--->
    //    p2 p1   q1
    //     s1     s2
    //         s
    // 从分治之后的返回值 s1 来看,最短距离的点 只有p1和p2 = d1
    // 而s2 的最短距离为 Integer.MAX_VALUE ,因为只有一个点,所以不存在
    // 那么可能的情况有
    // 1.p1和p2 是最近距离
    // 2.还有一个情况从s数组的分割线的角度考虑,s1未处理,s2也未处理的情况:s1 的最右侧点(p1) 和 s2 的最左侧点(q1) 之间的距离 dsgap,dsgap < d1,那么当前数组s中的最小距离ds = dsgap,否则 ds=d1
    //
    // n=4时
    //         ds
    //        dsgap (处于分割线两段的点的距离)
    //    ds1      ds2
    // ---*---*|--*--*--->
    //    p2 p1   q1 q2
    //     s1     s2
    //         s
    // 先计算 s1 最大序号顶点p1 和 s2 最小序号顶点 q1 之间的距离 dsgap
    // 然后找到 ds1 ,ds2 , dsgap 最小的值,作为当前数组s 的2点最短距离返回值 ds 并返回
    //
    // 当递归回溯到较高层的时候(n越来越大时)
    // n=5.6.7...更多
    //                  ds
    //                 dsgap (处于分割线两段的点的距离)
    //            ds1      ds2
    // ...--*---*--*---*|--*--*---*--*---->...
    //     p. p3  p2 p1   q1 q2   q3 q4 q.
    //             s1       s2
    //                  s
    // 此时同样需要计算dsgap的值
    // 不用知道s1中 ds1 具体是哪2个顶点之间的最小距离,只需知道ds1是左侧不断分治后,直到最小规模情况时返回的整个 s1 的最短距离
    // 同理 ds2 也是
    // 所以这种情况下找到 s 的 ds 的办法和上面一样
    // 1.根据 s1 的最右侧断点 p1 和 s2 最左侧端点 q1 的距离 dsgap
    // 2.找到 ds1 和 ds2 和 dsgap 的最短距离作为当前s 的最短距离 ds来返回
    //
    // 总结一下
    // 最小规模下
    // n=0,1
    // ds1,ds2 无值,dsgap 无值,ds 为 Integer.MAX_VALUE
    // n=2
    // ds1,ds2 无值,dsgap 无值,ds 为唯一2个点的距离
    // n=3,4,5...
    // ds1,ds2 可能存在有 Integer.MAX_VALUE 的情况(只分得了1一个点的情况)
    // dsgap 有值
    // ds = ds1,ds2,dsgap 的最小值 (Integer.MAX_VALUE 的无效值除外)
    // 代码:

    public static class Point {
        int x;
        int y;

        public Point(int x) {
            this.x = x;
        }

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return "{" +
                    "" + x + "," + y +
                    ‘}‘;
        }
    }

    private static void ms1D_Demo() {
        //在0~30的范围内,随机生成7个点,并排序
        Point[] points = new Point[7];
        Random r = new Random("996.251.404.go die".hashCode());
        for (int i = 0; i < points.length; i++)
            points[i] = new Point(r.nextInt(30));
        Arrays.sort(points, new Comparator<Point>() {
            @Override
            public int compare(Point lhs, Point rhs) {
                return lhs.x - rhs.x;
            }
        });
        System.out.println(Arrays.toString(points));

        int ds = minimumSpacing1D(points, 0, points.length - 1);
        System.out.println(ds);
    }

    public static int minimumSpacing1D(Point[] points, int l, int r) {
        //2.处理:处理最小规模
        int len = r - l;
        if (len < 1)                                    //1个点 返回无效值
            return Integer.MAX_VALUE;
        if (len < 2)                                    //2个点 返回这两个点的距离
            return points[r].x - points[l].x;

        //1.分割:此处对3个点及以上处理
        int m = (l + r) >> 1;
        int ds1 = minimumSpacing1D(points, l, m);         //分治左侧
        int ds2 = minimumSpacing1D(points, m + 1, r);  //分治右侧
        //3.合并:找到当前最短距离是多少
        int dsgap = points[m + 1].x - points[m].x;      //计算分割线两边的点距
        int ds = ds1 < ds2 ? ds1 : ds2;
        ds = dsgap < ds ? dsgap : ds;                   //保留最小点距并返回
        return ds;
    }
 public static void main(String[] ar) {
        ms1D_Demo();
    }
}

输出

[{0,0}, {5,0}, {8,0}, {9,0}, {17,0}, {21,0}, {25,0}]
1

2维情况

package com.ex.cy.demo4.alg.algthink.divide;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Random;

public class MinimumSpacing {

    public static class Point {
        int x;
        int y;

        public Point(int x) {
            this.x = x;
        }

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return "{" +
                    "" + x + "," + y +
                    ‘}‘;
        }
    }

    //============
    //  考虑2D情况
    //============
    //代码:

    public static void ms2d_Demo() {
        System.out.println("\n======ms2d_Demo======");
        Point[] points = new Point[7];
        Random r = new Random("996.251.404.go die".hashCode());
        for (int i = 0; i < points.length; i++) {
            points[i] = new Point(r.nextInt(40), r.nextInt(40));
        }

        Arrays.sort(points, new Comparator<Point>() {
            @Override
            public int compare(Point lhs, Point rhs) {
                //先按x排序
                int dx = lhs.x - rhs.x;
                int dy = lhs.y - rhs.y;
                if (dx == 0)
                    return dy;      //x值相同,按照y值小的排在数组靠前
                return dx;          //x值不同,按照x值小的排在数组靠前
            }
        });
        System.out.println(Arrays.toString(points));

        float ds = minimumSpacing2D(points, 0, points.length - 1);
        System.out.println(ds);
    }

    public static float minimumSpacing2D(Point[] points, int l, int r) {
        //2.处理:处理最小规模
        int len = r - l;
        if (len < 1)                                        //1个点 返回无效值
            return Float.POSITIVE_INFINITY;
        if (len < 2) {                                      //2个点 返回这两个点的距离
            float dst = dst2D(points[r], points[l]);
            System.out.println("dst " + dst);
            return dst;
        }

        //1.分割:此处对3个点及以上处理
        int m = (l + r) >> 1;
        float ds1 = minimumSpacing2D(points, l, m);         //分治左侧
        float ds2 = minimumSpacing2D(points, m + 1, r);  //分治右侧
        //3.合并:找到当前最短距离是多少
        float ds = ds1 < ds2 ? ds1 : ds2;

        //根据鸽巢原理,另一边用ds画1个 d*2d的矩形,那么在该矩形内不会超过6个点(如果超过的话,根据ds的定义,会产生矛盾)
        //也就是说一次合并最多用s2内的,以m为轴,以d为距离,在m的右侧,间隔d的地方画一条平行于m的线 p2
        //在p2内任意一点,若存在和[m-ds,m]中有比ds更短距离的匹配,那么不会超过6次匹配
        LinkedList<Point> pointXfromMtods = new LinkedList();
        for (int i = l; i < r; i++) {
            //只对以m:x为中心,+- ds为x范围的点处理,在这个范围内的点,两两比较,试着找到间距小于ds的点对
            if (Math.abs(points[i].x - points[m].x) <= ds)
                pointXfromMtods.add(points[i]);
        }
        //按y值升序排序
        Collections.sort(pointXfromMtods, new Comparator<Point>() {
            @Override
            public int compare(Point lhs, Point rhs) {
                return lhs.y - rhs.y;
            }
        });
        System.out.println("pointXfromMtods " + pointXfromMtods);

        for (int i = 0; i < pointXfromMtods.size(); i++) { //找,的x或y 之间距离小于ds的点对
            for (int j = i + 1; j < pointXfromMtods.size(); j++) {
                int dy = Math.abs(pointXfromMtods.get(j).y - pointXfromMtods.get(i).y);
                if (dy > ds)
                    break;              //若发现一个和[i]点的y值 之差 > ds 的,说明已经超出了范围,进入下一个[i]的遍历检测
                int dx = Math.abs(pointXfromMtods.get(j).x - pointXfromMtods.get(i).x);
                float dsgap = (float) Math.sqrt(dx * dx + dy * dy);
                System.out.println("dsgap " + ds);
                ds = ds < dsgap ? ds : dsgap;
            }
        }

        System.out.println("ds " + ds);
        return ds;
    }

    //返回2d空间中 a,b两点的距离
    public static float dst2D(Point a, Point b) {
        int xx = a.x - b.x;
        xx *= xx;
        int yy = a.y - b.y;
        yy *= yy;
        return (float) Math.sqrt(xx + yy);
    }

    public static float dst(int x, int y) {
        return (float) Math.sqrt(x * x + y * y);
    }

    public static void main(String[] ar) {
        ms2d_Demo();
    }
}
[{0,8}, {5,4}, {7,8}, {11,37}, {20,38}, {35,9}, {35,17}]
4.472136

原文地址:https://www.cnblogs.com/cyy12/p/11991978.html

时间: 2024-10-03 04:35:57

给定数轴上的n个点,求距离最近的两个点的距离的相关文章

求二叉树中任意两个结点的距离

求二叉树中任意两个结点的距离 实现步骤: 计算跟到第一个结点的距离: 计算跟到第二个结点的距离: 计算lca: 计算跟到lca结点的距离: 结果为(1) + (2) - 2 * (4),因为重复计算了两次的从跟到lca结点的距离: 1 class Node(object): def __init__(self, value=0): self.value = value self.left = self.right = None def get_path_length(root, n, path)

JAVA实现求一点到另两点连线的距离,计算两点之间的距离

直接上代码 /** *计算两点之间距离 */ public static double getDistance(Point start,Point end){ double lat1=start.getX().doubleValue(); double lat2=end.getX().doubleValue(); double lon1=start.getY().doubleValue(); double lon2=end.getY().doubleValue(); return Math.sq

N个未排序的随机数,在线性时间内,求这N个数在数轴上相邻两个数的最大值

1 public class MaxSub 2 { 3 public static void main(String[] args) 4 { 5 int[] a ={5,7,3,1,6,2}; 6 System.out.println(maxSub(a)); 7 8 } 9 10 /** 11 * @用于找出N个随机数在数轴相邻位置的最大差值 12 */ 13 public static int maxSub(int[] a) 14 { 15 int min=a[0];//初始化数组的最小值mi

给定N个整数的序列,求函数的最大值

题目:给定N个整数的序列,求函数的最大值. 算法1: int maxSubseqSum1(int A[],int N) { int ThisSum,maxSum=0; int i,j,k; for(i=0;i<N;i++)//i是子列左端位置 { for(j=i;i<N;j++)//j是子列右端位置 { ThisSum=0;//ThisSum是从A[i]到A[j]的子列和 for(k=i;k<=j;k++) ThisSum+=A[k]; if(ThisSum>MaxSum)//如果

hdu5795 A Simple Nim 求nim求法,打表找sg值规律 给定n堆石子,每堆有若干石子,两个人轮流操作,每次操作可以选择任意一堆取走任意个石子(不可以为空) 或者选择一堆,把它分成三堆,每堆不为空。求先手必胜,还是后手必胜。

/** 题目:A Simple Nim 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5795 题意:给定n堆石子,每堆有若干石子,两个人轮流操作,每次操作可以选择任意一堆取走任意个石子(不可以为空) 或者选择一堆,把它分成三堆,每堆不为空.求先手必胜,还是后手必胜. 思路: 组合游戏Nim: 计算出每一堆的sg值,然后取异或.异或和>0那么先手,否则后手. 对于每一堆的sg值求解方法: 设:sg(x)表示x个石子的sg值.sg(x) = mex{sg

9.7数学与概率(一)——给定直角坐标上的两条线,确定这两条线会不会相交

/** * 功能:给定直角坐标上的两条线,确定这两条线会不会相交. */ public class Line { static double epsilon=0.000001; public double slope;//斜率 public double yintercept;//与y轴的截距 public static void main(String[] args) { // TODO Auto-generated method stub } /** * 假设: * 1)若两条线是相同的(斜

HDU 4355 数轴上的点找使Si^3*Wi最小的和-浮点数三分

题意:一个数轴上有n个点,现在要找一个点到所有点的距离Si的立方乘以点的权Wi的和最小 分析:三分.浮点数的二分或者三分可以直接用一个数字来限制查找的次数.TLE了几次,把查找次数从10000改到100就过了,本来以为数据范围比较大,100的精度不够. 代码: #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #def

25.(需要好好研究研究)输入任意的正整数,将其各位分离出来;求它是几位数,求各位上数字的和,求其逆值

#include<iostream> using namespace std; int main() { int m,n,i,j=1,k=0,a[20],x,y; cout<<"请输入一个整数:"; cin>>m;//输入的数为m y=m;//先将m赋值给y,将原始输入的数保护起来 for(i=1;;i++)//中间的判断条件可以不要,就变成了死循环 { j*=10; n=m/j; a[i]=n; k++;//用于记录有几位数 if(n<1)/

求一个序列中两个只出现一次的数

当然了,O(1)空间复杂度是必须的... 先看一个简单版: 求出一个序列中一个只出现一次的数 COJ 1217 奇数个的那个数 http://122.207.68.93/OnlineJudge/problem.php?id=1217 我们知道任意两个相同的数 异或结果为0  任何数与0异或结果是其本身  异或运算满足交换律 亦即:a^a=0     a^0=a      (a^b)^(a^b)=(a^a)^(b^b)=0^0=0 这样我们就得到了一个用异或运算的解法 1 #include<std