我写这个文章首先是为了记录自己做题思考的过程,同时也想要为一些同我一样刚开始刷题的同学提供一些解题思路。如果哪里写的有问题,欢迎指正。谢谢!
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:
- 你可以假设
nums
中的所有元素是不重复的。 n
将在[1, 10000]
之间。nums
的每个元素都将在[-9999, 9999]
之间。
二分查找过程:
查找的范围为[left,right],每次查找去left和right的中间值mid,如果要查找的值target=nums[mid],则mid就是所要寻找的下标。如果target<nums[mid],则target处在[left,mid]范围之中,舍弃掉了[mid,right],因此查找范围缩小一半,大大提高了查找效率。如果target>nums[mid],同理可推target处在[mid,right]中,就可以舍弃掉[left,mid]。
这样看图片可能会更清楚一些,从上图可以看出二分查找相较于直接查找更快一些,不用一个个进行比较。
但是要注意二分查找只适用与有序的线性表, 如果无序或者是链表是不可以的,相信这很容易就可以想明白
我的答案:(错误示范)
class Solution {
public int search(int[] nums, int target) {
//因为是升序,是有序的。若数据不在数组中可以直接排除
if(target<nums[0] || target>nums[nums.length-1]){
return -1;
}
//int left=nums[0];
//int right=nums[nums.length-1];
//错了,left和right对应得是下标,不是对应的某个数
int left=0;
int right=nums.length-1;
int mid=(left+right)/2;
//if语句应该嵌套在一个循环里面,否则执行一遍就结束了
while(left<=right){
if(target==nums[mid]){
return mid;
}else if(target>nums[mid]){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;
}
}
这里代码执行结果是超出时间限制
现在要看一下哪里有问题,先不要提交,不然提交也是不通过
首先mid的位置有问题,如果把取中间值放在while循环外面,他就只执行一次,显然这与我们的思想是不符的,应该把mid放到循环中去,我们再试一下。
(正确答案)
class Solution {
public int search(int[] nums, int target) {
//因为是升序,是有序的。若数据不在数组中可以直接排除
if(target<nums[0] || target>nums[nums.length-1]){
return -1;
}
//int left=nums[0];
//int right=nums[nums.length-1];
//错了,left和right对应得是下标,不是对应的某个数
int left=0;
int right=nums.length-1;
//if语句应该嵌套在一个循环里面,否则执行一遍就结束了
while(left<=right){
int mid=(left+right)/2;
if(target==nums[mid]){
return mid;
}else if(target>nums[mid]){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;
}
}
ok,执行通过了
另外我们还可以改写一下mid
//int mid=(left+right)/2;
int mid = (right-left)/2+left;