查找算法
二分查找
前提是数组有序,二分查找时间复杂度O(logN)
func BinarySearch(data []int, target int) int {
var low, high, mid int
low, high = 0, len(data) - 1
for low <= high {
mid = low + (high-low)/2 //防止溢出
if data[mid] > target {
high = mid - 1
} else if data[mid] < target {
low = mid + 1
} else {
return mid
}
}
return -1
}
如果有序数组里面有重复数字,要查找重复数字的左右边界,可基于上述二分查找算法略加修改即可。
如查找左边界:return mid 处改为 high=mid-1,return -1 处改为 return low。另外需要加一段判断left越界情况的逻辑 if left > len(data)-1 || data[left] != target 则return -1
TopK问题
quick select 快速选择算法
quick select 算法的主要目的是在一个没有排序的数组里面,找到第k小的元素。
快速选择的总体思路与快速排序一致,选择一个元素作为基准来对元素进行分区,将小于和大于基准的元素分在基准左边和右边的两个区域。不同的是,快速选择并不递归访问双边,而是只递归进入一边的元素中继续寻找。这降低了平均时间复杂度,从O(n log n)至O(n),不过最坏情况仍然是O(n2)。
func quickselect(nums []int, start, end, k int) int {
// use last element as pivot
pivotIndex := partition(nums, start, end, end)
if k-1 == pivotIndex {
return nums[pivotIndex]
} else if k-1 > pivotIndex {
return quickselect(nums, pivotIndex+1, end, k)
} else {
return quickselect(nums, start, pivotIndex-1, k)
}
}
func partition(nums []int, start, end, pivot int) int {
// move pivot to end
nums[end], nums[pivot] = nums[pivot], nums[end]
pivotValue := nums[end]
i := start
for j := start; j < end; j++ {
if nums[j] > pivotValue {
nums[i], nums[j] = nums[j], nums[i]
i++
}
}
// move pivot to its sorted position
nums[i], nums[end] = nums[end], nums[i]
// return pivot index
return i
}