github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/dp/least_point_test.go (about)

     1  package dp
     2  
     3  import (
     4  	"math"
     5  	"sort"
     6  	"testing"
     7  )
     8  
     9  /*
    10  
    11  分治思想
    12  分解:将原问题分解成一系列子问题;
    13  解决:递归地求解各个子问题,若子问题足够小,则直接独立求解;
    14  合并:将子问题的结果合并成原问题
    15  
    16  最近点问题
    17  借助 归并排序的思想
    18  */
    19  
    20  // 1. 求 数轴上最近两点的距离 (有序的数)
    21  func Test_leastPointOnAxis(t *testing.T) {
    22  	axis := []float64{1, 5, 8, 11, 13, 15}
    23  	t.Log(leastPointOnAxis(axis))
    24  }
    25  
    26  func leastPointOnAxis(axis []float64) float64 {
    27  	n := len(axis)
    28  	if n < 2 {
    29  		return 0
    30  	}
    31  	return calcLeastPoint(axis, 0, n-1)
    32  }
    33  
    34  func calcLeastPoint(axis []float64, p, r int) float64 {
    35  	if p+1 >= r { // 只有2个点时
    36  		return math.Abs(axis[r] - axis[p])
    37  	}
    38  	if p+2 >= r { // 三个点的时候
    39  		return math.Min(math.Abs(axis[p+1]-axis[p]), math.Abs(axis[r]-axis[p+1]))
    40  	}
    41  	mid := p + ((r - p) >> 1)
    42  	min1 := calcLeastPoint(axis, p, mid)   //左边最小
    43  	min2 := calcLeastPoint(axis, mid+1, r) // 有右边最小
    44  	// 左右缝隙的距离
    45  	return math.Min(min1, math.Min(min2, math.Abs(axis[mid+1]-axis[mid])))
    46  }
    47  
    48  //2. n个点在公共空间中,求出所有点对的欧几里得距离最小的点对。
    49  //思路: 一样使用分治法, 按照 x ,y 两个轴进行切分
    50  // https://blog.csdn.net/sinat_35678407/article/details/82874216
    51  
    52  type Point struct {
    53  	x, y float64
    54  }
    55  
    56  // 两点之间的距离
    57  func distance(p1, p2 Point) float64 {
    58  	return math.Sqrt(math.Pow(p1.x-p2.x, 2) + math.Pow(p1.y-p2.y, 2))
    59  }
    60  
    61  func leastPointDistance(points []Point) float64 {
    62  	// 找出x y分别的最大最小值
    63  	n := len(points)
    64  	if n < 2 {
    65  		return 0
    66  	}
    67  	if n == 2 {
    68  		return distance(points[0], points[1])
    69  	}
    70  	if n == 3 {
    71  		return math.Min(distance(points[0], points[1]),
    72  			math.Min(distance(points[0], points[2]), distance(points[1], points[2])))
    73  	}
    74  	// 进行区域划分
    75  	mid := n>>1 - 1
    76  	d1 := leastPointDistance(points[:mid+1])   // 左区域
    77  	d2 := leastPointDistance(points[n-mid-1:]) // 右区域
    78  	d := math.Min(d1, d2)                      // 左右区域缝隙的点进行比较
    79  	return merge(points, d, mid)
    80  }
    81  
    82  // 合并比较
    83  func merge(points []Point, minDic float64, mid int) float64 {
    84  	var left, right []Point
    85  	// 左右进行分区 对x轴进距离筛选,距离要小于minDic
    86  	for i := range points {
    87  		if points[i].x <= points[mid].x && math.Abs(points[i].x-points[mid].x) < minDic { // 左边区域
    88  			left = append(left, points[i])
    89  		} else if points[i].x > points[mid].x && math.Abs(points[i].x-points[mid].x) < minDic { //右边区域
    90  			right = append(right, points[i])
    91  		}
    92  	}
    93  	// 对右边y轴进行排序
    94  	sort.Slice(right, func(i, j int) bool {
    95  		return right[i].y > right[j].y
    96  	})
    97  
    98  	// 用左边区域的每个点跟右边区域符合条件的点进行比较
    99  	for i := range left {
   100  		index := 0
   101  		for ; index < len(right) && left[i].y < right[index].y; index++ {
   102  			// 左边的点y轴的高度 要高于 右边区域的才进行比较
   103  		}
   104  		for j := range right { // 右边区域
   105  			if j > 6 || index+j >= len(right) { // 遍历右边坐标y轴方向上 距离上界最近的的6个点
   106  				break
   107  			}
   108  			calcDis := distance(left[i], right[j+index])
   109  			if calcDis < minDic {
   110  				minDic = calcDis
   111  			}
   112  		}
   113  	}
   114  	return minDic
   115  }
   116  
   117  func Test_leastPointDistance(t *testing.T) {
   118  	var points []Point
   119  	points = append(points, Point{0, 15})
   120  	points = append(points, Point{0, 23})
   121  	points = append(points, Point{1, 0.7})
   122  	points = append(points, Point{0, 1.8})
   123  
   124  	sort.Slice(points, func(i, j int) bool {
   125  		return points[i].x > points[j].x
   126  	})
   127  	leastDis := leastPointDistance(points)
   128  	t.Log("最短距离 ", leastDis)
   129  }