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 }