目录
题目:
一、二分查找
- 解题思路:
- nums为升序数组, 比较nums[i]与target: num[i] > target --- 在下标i的左侧寻找; num[i] < target --- 在下标i的右侧寻找; num[i] = target --- 返回下标i;
- 二分查找法:设置查找范围为[low,high],每次查找查找范围的中点mid,比较nums[mid]和target,相等返回i,不相等根据target与nums[mid]的大小缩小查找范围为一半;
- 返回值:在查找范围不为空的情况下(即,low<=high),查找到结果,返回target对应的下标(值相等时的mid);low>high时未查找到等值,target未在数组中,返回-1。
- 代码:
class Solution { public int search(int[] nums,int target) { int low = 0, high = nums.length-1; while(low <= high){ int mid = low + (high-low)/2; //不能用(low+high)/2形式,当low和high都是int,两个值的初始值都超过int限定大小的一半,那么low+high就会发生溢出,所以应该用low+(high-low)/2来防止求中值时候的溢出 if(nums[mid] > target) { high = mid - 1; } else if (nums[mid] < target) { low = mid + 1; } else { return mid; } } return -1; } }
- 复杂度分析:
- 时间复杂度:每次查找会将查找范围缩小一半,时间复杂度为O(log n) ,n为数组长度
- 空间复杂度:O(1)
二、第一个错误的版本
- 解题思路:
- 在1111111...0000000...中查找第一个错误版本,正确版本之前的全为正确版本,错误版本之后的全为错误版本;
- 二分查找法:设置查找范围[low,high],最初范围[1,N],每次查找中间值mid,查找为正确版本时,结果在此版本右侧([low,mid]之间);查找为错误版本时,结果在此版本左侧([mid+1,high]之间);
- 返回值:直至low = high时,查找到结果,low和high均为返回值。
- 代码
/* The isBadVersion API is defined in the parent class VersionControl. boolean isBadVersion(int version); */ public class Solution extends VersionControl { public int firstBadVersion(int n) { int low = 1, high = n; while(low < high) { int mid = low + (high - low) / 2; if(isBadVersion(mid)){ high = mid; } else { low = mid + 1; } } return high; } }
- 复杂度分析
- 时间复杂度:每次查找会将查找范围缩小一半,时间复杂度为O(log n) ,n为数组长度
- 空间复杂度:O(1)
三、搜索插入位置
- 解题思路:
- 直接用二分查找法,不过要考虑目标值不存在于数组中的情况;
- 返回值:在查找范围不为空的情况下(即,low<=high),查找到结果,返回target对应的下标(值相等时的mid);low>high时未查找到等值,返回它将会被按顺序插入的位置(即最终的low值)。
- 代码
class Solution { public int searchInsert(int[] nums, int target) { int low = 0, high = nums.length - 1; while(low <= high){ int mid = low + (high - low) / 2; if(nums[mid] > target) { high = mid - 1; } else if (nums[mid] < target) { low = mid + 1; } else { return mid; } } return low; } }
- 复杂度分析
- 时间复杂度:每次查找会将查找范围缩小一半,时间复杂度为O(log n) ,n为数组长度
- 空间复杂度:O(1)
总结
- 二分查找中,mid赋值时使用low+(high-low)/2,不使用(low+high)/2防止当low和high都是int型,且值都超过int的一半时,发生溢出。