第一篇:二分查找
看到排序数组或者部分排序数组,或者时间复杂度要求O(log n),应该第一时间想到二分查找。
在无重复的排序数组中找特定值的索引:
func binarySearch(nums []int, target int) int { left := 0 right := len(nums) - 1 for left <= right { mid := left + (right-left)/2 if target == nums[mid] { return mid } else if target < nums[mid] { right = mid - 1 } else { left = mid + 1 } } return -1 }
在有重复的排序数组中找第一个大于等于特定值的元素的索引:
func lowerBound(nums []int, target int) int { l, r := 0, len(nums) for l < r { mid := l + (r-l)/2 if nums[mid] < target { l = mid + 1 } else { r = mid } } return l }
这两个模板的区别在于:
第一个模板right初始值是数组长度减1,即表示
部分有序也可尝试使用二分查找及其变种。
力扣35、搜索插入位置。easy
用while循环,不满足条件后跳出循环。
力扣33、搜索旋转排序数组。medium
根据题意,旋转后的数组各元素值是先递增,然后陡降到最小,最后再递增。把索引当成x轴,把元素值当成y轴,画一个二维图就一目了然了。
如果中间位置处的元素值比最左侧元素值大,则说明左半边数组(从left开始,到mid结束,包括left和mid)是递增的,右半边数组(从mid开始,到right结束,包括mid和right)是先减后增,或者是先增后减再增。
反之,如果中间位置处的元素值比最左侧元素值小,则说明右半边数组(从mid开始,到right结束,包括mid和right)是递增的,左半边数组(从left开始,到mid结束,包括left和mid)是先增后减,或者是先增后减再增。
以上两种情况,我们先到递增的那半边数组中搜索目标值,如果找到,就返回,否则,再到另半边数组中去找。到另半边数组中去找的时候,还是把这半边数组从中间分割成两部分,
力扣4、寻找两个正序数组的中位数。hard
思路:在两个数组中各画一条分隔线,使得两数组在分隔线左边的元素个数之和等于分隔线右边的元素个数之和,或者比右边元素个数之和大1,分别对应两数组元素之和为偶数和奇数的情况。这样的分隔线有很多,假设第一个数组有3个元素,第二个数组有5个元素,那么分隔线左右两边的元素个数之和都为4。
分隔线可能的情况如下:
第一个数组的分隔线在最左边,即分隔线左边没有元素,分隔线右边有3个元素,第二个数组的分隔线左边就得有4个元素,右边有1个元素。
第一个数组的分隔线左边有1个元素,分隔线右边有2个元素,第二个数组的分隔线左边就得有3个元素,右边有2个元素。
第一个数组的分隔线左边有2个元素,分隔线右边有1个元素,第二个数组的分隔线左边就得有2个元素,右边有3个元素。
第一个数组的分隔线左边有3个元素,分隔线右边没有元素,第二个数组的分隔线左边就得有1个元素,右边有4个元素。
浙公网安备 33010602011771号