【算法基础】二分查找
二分查找算法利用数组的二段性,也就是数组可以被根据一定的规律分为两段,这两段具有不同的性质。
时间复杂度:
1次循环 ---> 剩 n/2
2次循环 ---> 剩 n/4
3次循环 ---> 剩 n/8
......
m次循环 ---> 剩 1
1 = n/n = n/(2的m次方)
m = logn
1. 基础二分查找
704. 二分查找 - 力扣(LeetCode)
class Solution {public int search(int[] nums, int target) {int head = 0, tail = nums.length - 1;while (head <= tail) {int mid = head + (tail - head) / 2;if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {tail = mid - 1;} else {head = mid + 1;}}return -1;}
}
2. 二分查找左端点
当 nums[mid] < target,此时 mid 落在的地方一定不是我们想要的。左端点一定在 (mid, tail) 中。
当 nums[mid] >= target,有可能此时 mid 已经踩在了左端点,也有可能左端点尚在 mid 的左边。左端点一定在 (head, mid] 中。
查找左端点时计算 mid 必须取左,因为 tail 每次会踩到 mid 上,如果 mid 取右,当 mid 与 tail 重合时会死循环。
public int searchLeft(int[] nums, int target) {int head = 0, tail = nums.length - 1;while (head < tail) {int mid = head + (tail - head) / 2;if (nums[mid] < target) {head = mid + 1;} else {tail = mid;}}if (nums[head] == target && nums[tail] == target)return head;return -1;}
35. 搜索插入位置 - 力扣(LeetCode)
二段性:前一段中的元素均小于 target,后一段的元素均大于等于 target。
找大于等于 target 的左端点。
162. 寻找峰值 - 力扣(LeetCode)
二段性:由于题目只需要返回一个结果,任取一座山分析即可。每座山都能被分为上升区间和下降区间。
找递减区间的左端点。判断条件应使用 nums[mid] 和 nums[mid + 1] 进行比较,因为查找左端点时 mid 要取左,比较时应取 mid 右面的元素。
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)
二段性:前一段中的元素均大于数组中的末位数,后一段中的元素均小于等于数组中的末位数。
找小于等于数组末位数的左端点。
LCR 173. 点名 - 力扣(LeetCode)
二段性:前一段元素 val = index,后一段元素 val = index + 1。
找元素 val = index + 1 区间的左端点。
3. 二分查找右端点
当 nums[mid] > target,此时 mid 落在的地方一定不是我们想要的。右端点一定在 (head, mid) 中。
当 nums[mid] <= target,有可能此时 mid 已经踩在了右端点,也有可能右端点尚在 mid 的右边。右端点一定在 [mid, tail) 中。
查找右端点时计算 mid 必须取右,因为 head 每次会踩到 mid 上,如果 mid 取左,当 mid 与 head 重合时会死循环。
public int searchRight(int[] nums, int target) {int head = 0, tail = nums.length - 1;while (head < tail) {int mid = head + (tail - head + 1) / 2;if (nums[mid] > target) {tail = mid - 1;} else {head = mid;}}if (nums[head] == target && nums[tail] == target)return head;return -1;}
69. x 的平方根 - 力扣(LeetCode)
二段性:前一段区间中元素的平方均小于等于 x,后一段区间中元素的平方均大于 x。
找元素平方小于等于 x 的右端点。
注意:指针即是 val,不需要创建数组。数据需要用 long 接收。