二分查找
猜数字游戏:
每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
返回我选出的数字。
注意:需要调用guess(int num)函数来辅助判断
public class Solution extends GuessGame {
public int guessNumber(int n ) {
int left=0;
int right=n;
while(left<=right){
//求出中间值 (防止整数数据溢出) - 整数向下取整
int mid=left+(right-left)/2;
int result=guess(mid);
if(result==0){
return mid;
}
//你猜的数字偏大,区间位于中间值左边
if(result==-1){
right= mid-1;
}
//你猜的数字偏小,区间位于中间值右边
if(result==1){
left= mid+1;
}
}
return -1;
}}
搜索插入位置
public class Solution {
public int searchInsert(int[] nums, int target) {
int len = nums.length;
// 题目没有说输入数组的长度可能为 0,因此需要做特殊判断
if (len == 0) {
return 0;
}
// 在区间 [left, right] 查找插入元素的位置
int left = 0;
// 注意:这里初始值设置为 len,表示 len 这个下标也有可能是插入元素的位置
int right = len;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target){
// 下一轮搜索的区间是 [mid + 1, right]
left = mid + 1;
} else {
// 下一轮搜索的区间是 [left, mid]
right = mid;
}
}
// 由于程序走到这里 [left, right] 里一定存在插入元素的位置
// 且退出循环的时候一定有 left == right 成立,因此返回 left 或者 right 均可
return left;
}
}
复杂度分析:
- 时间复杂度:O(\log N)O(logN),这里 NN
是数组的长度,每一次都将问题的规模缩减为原来的一半,因此时间复杂度是对数级别的; - 空间复杂度:O(1)O(1),使用到常数个临时变量。
- 由于下标 len
这个位置,也有可能是插入元素的位置,于是可以省去最开始的特殊判断,通过两边 逼近 的方式找到插入元素的位置。
作者:liweiwei1419
链接:https://leetcode-cn.com/leetbook/read/learning-algorithms-with-leetcode/xs1z3v/