二分查找的实现、特性及 力扣实战题目解析

二分查找的前提
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 ②如果[0,mid]存在旋转序列即nums[0]>nums[mid] 时 :若 targetmums[mid]) ,向后规约
③其余情况为向前规约
循环判断,排除剩余最后一个元素时退出循环,找到返回下标,未找到返回-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;
	}

你可能感兴趣的:(数据结构与算法,二分法)