github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/binary_search/binary_search.go (about) 1 package binary_search 2 3 import "math" 4 5 /* 6 二分查找 7 有点类似于数学中的夹逼定理, 两边不断逼近某个值 8 9 十个二分九个错 10 11 时间复杂度 12 2^k = n 第 k次可以找到该元素 13 k = log2n 所以 O(logn) 14 15 */ 16 func BSearch(arr []int, val int) int { 17 n := len(arr) 18 if n < 1 { 19 return -1 20 } 21 low := 0 22 high := n - 1 23 for low <= high { // 注意是 <= 不是 < 24 mid := low + ((high - low) >> 1) 25 if arr[mid] == val { 26 return mid 27 } else if arr[mid] < val { 28 low = mid + 1 // 注意需要+1 29 } else { 30 high = mid - 1 31 } 32 } 33 return -1 34 } 35 36 // 二分查找递归写法 37 func BSearchRecusion(arr []int, val int) int { 38 n := len(arr) 39 if n < 1 { 40 return -1 41 } 42 return bsearchR(arr, val, 0, n-1) 43 } 44 45 func bsearchR(arr []int, val, low, high int) int { 46 if low > high { 47 return -1 48 } 49 mid := low + ((high - low) >> 1) 50 if arr[mid] == val { 51 return mid 52 } else if arr[mid] < val { 53 return bsearchR(arr, val, mid+1, high) 54 } else { 55 return bsearchR(arr, val, low, mid-1) 56 } 57 } 58 59 // 二分法求平方根 60 func BSqrt(x float64, precise float64) float64 { 61 if x <= 0 { 62 if x == 0 { 63 return 0 64 } 65 return -1 66 } 67 // 大于1 在 0~x 之间查找 68 low := 0.0 69 high := x 70 if x < 1 { 71 // 小于1 在 x~1 之间查找该值 72 low = x 73 high = 1 74 } 75 mid := x / 2.0 76 for math.Abs(mid*mid-x) > precise { 77 if mid*mid < x { 78 low = mid 79 } else { 80 high = mid 81 } 82 mid = (low + high) / 2.0 83 } 84 return mid 85 } 86 87 /* 88 二分查找的 变体(里面有重复值时) 89 变体1. 查找第一个值等于给定值的元素 90 */ 91 func BSearchFirst(arr []int, val int) int { 92 n := len(arr) 93 if n < 1 { 94 return -1 95 } 96 low := 0 97 high := n - 1 98 for low <= high { 99 mid := low + ((high - low) >> 1) 100 if arr[mid] > val { 101 high = mid - 1 102 } else if arr[mid] < val { 103 low = mid + 1 104 } else { 105 //如果 mid 等于 0,那这个元素已经是数组的第一个元素,那它肯定是我们要找的 106 //如果 mid 不等于 0,但 a[mid] 的前一个元素 a[mid-1] 不等于 value,那也说明 107 //a[mid] 就是我们要找的第一个值等于给定值的元素 108 if mid == 0 || arr[mid-1] != val { 109 return mid 110 } else { 111 // 需要找的范围肯定 [low,mid]范围,但需要找第一个所以往前逼近 112 // 所以近一步向前缩小范围 [low, mid -1] 113 high = mid - 1 114 } 115 } 116 } 117 return -1 118 } 119 120 // 烧脑的写法 121 func BSearchFirst2(arr []int, val int) int { 122 n := len(arr) 123 if n < 1 { 124 return -1 125 } 126 low := 0 127 high := n - 1 128 for low <= high { 129 mid := low + ((high - low) >> 1) 130 if arr[mid] >= val { 131 high = mid - 1 132 } else { 133 low = mid + 1 134 } 135 } 136 if arr[low] == val { 137 return low 138 } 139 return -1 140 } 141 142 /* 143 变体2:查找最后一个值等于给定值的元素 144 */ 145 func BSearchLast(arr []int, val int) int { 146 n := len(arr) 147 if n < 1 { 148 return -1 149 } 150 low := 0 151 high := n - 1 152 for low <= high { 153 mid := low + ((high - low) >> 1) 154 if arr[mid] > val { 155 high = mid - 1 156 } else if arr[mid] < val { 157 low = mid + 1 158 } else { 159 // 数组最后一个, 后面一个又不等于需要的值 160 if mid == n-1 || arr[mid+1] != val { 161 return mid 162 } else { //向后逼近 163 low = mid + 1 164 } 165 } 166 } 167 return -1 168 } 169 170 /* 171 变体3:查找第一个大于等于给定值的元素 172 */ 173 func BSearchFirstGeVal(arr []int, val int) int { 174 n := len(arr) 175 if n < 1 { 176 return -1 177 } 178 low := 0 179 high := n - 1 180 for low <= high { 181 mid := low + ((high - low) >> 1) 182 if arr[mid] >= val { // 大于等于某个值 183 // 数组的第一个 ,前面一个又小于该值 184 if mid == 0 || arr[mid-1] < val { 185 return mid 186 } else { 187 // 向前逼近 188 high = mid - 1 189 } 190 } else if arr[mid] < val { 191 low = mid + 1 192 } 193 } 194 return -1 195 } 196 197 // 查找第一个大于 给定值的下标 198 func BSearchFirstGVal(arr []int, val int) int { 199 n := len(arr) 200 if n < 1 { 201 return -1 202 } 203 low := 0 204 high := n - 1 205 for low <= high { 206 mid := low + ((high - low) >> 1) 207 if arr[mid] > val { 208 high = mid - 1 209 } else { 210 low = mid + 1 211 } 212 } 213 return low 214 } 215 216 /* 217 变体4:查找最后一个小于等于给定值的元素 218 */ 219 func BSearchLastLeVal(arr []int, val int) int { 220 n := len(arr) 221 if n < 1 { 222 return -1 223 } 224 low := 0 225 high := n - 1 226 for low <= high { 227 mid := low + ((high - low) >> 1) 228 if arr[mid] > val { 229 high = mid - 1 230 } else if arr[mid] <= val { 231 // 数组最后一个, 后面一个又大于需要的值 232 if mid == n-1 || arr[mid+1] > val { 233 return mid 234 } else { //向后逼近 235 low = mid + 1 236 } 237 } 238 } 239 return -1 240 }