二分查找的前提:
1.目标函数单调性(单调递增或递减)
2.存在上下界(bounded)
3.能够通过索引访问(index accessible)
代码模版
left , right = 0,len(array) - 1
while left <= right:
mid = (left+right) / 2
if array[mid] == target:
# find the target!!
break or return result
elif array[mid] < target:
left = mid + 1
else:
right = mid - 1
应用二分查找的相关题及解:
例题1 : 添加链接描述
33.搜索旋转排序数组
题目描述:假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1::
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
题解:
题目要求时间复杂度为O(log n),故用二分查找,定义三个变量:left right mid 来判断指针向后还是向前规约
如果target在[mid+1,right]序列中,则 left=mid+1,否则right=mid,判断target在[mid+1,right]序列中的方式如下:
①如果[0,mid]为升序序列即nums[0]<=nums[mid] 时 :若 target>nums[mid]||target
③其余情况为向前规约
循环判断,排除剩余最后一个元素时退出循环,找到返回下标,未找到返回-1
实现:二分法( 时间复杂度为O(log(n)) , 执行时间 0ms)
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { //向后规约
left = mid + 1;
} else if (target > nums[mid] && target < nums[0]) {//向后规约
left = mid + 1;
} else {
right = mid;
}
}
return left == right && nums[left] == target ? left : -1;
}
}
例题2:
添加链接描述
69.X的平方根
题目描述:实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1: 输入: 4
输出: 2
示例 2: 输入: 8
输出: 2
说明: 8 的平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。
实现:
解法方案一:二分法( 时间复杂度为O(lg(x)) , 执行时间 2ms)
public int mySqrt(int x) {
int left = 1, right = x;
while (left <= right) {
int mid = left + (right - left) / 2;
if (mid == x / mid) {
return mid;
} else if (mid < x / mid) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return right;
}
解决方案二:牛顿法(时间复杂度O(lg(x)) , 执行时间 2ms)
public int mySqrt(int x) {
if (x == 0)
return 0;
long i = x;
while (i > x / i)
i = (i + x / i) / 2;
return (int) i;
}
解决方案三:暴力(时间复杂度O(sqrt(x)) , 执行时间 178ms)
public int mySqrt(int x) {
if (x == 0)
return 0;
for (int i = 1; i <= x / i; i++)
if (i <= x / i && (i + 1) > x / (i + 1))
return i;
return -1;
}