开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
今天刷一道力扣上简单的算法题,毕竟我是小白,从基础刷起,一步一个脚印
704. 二分查找
给定一个 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]之间。
首先我自己做了一遍,当然这不是二分查找,只是最简单的遍历查找。
class Solution {
public int search(int[] nums, int target) {
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
return i;
}
}
return -1;
}
}
那么下面进入正题,如何用二分查找法来解决这道题?
前提
首先我们需要知道一个前提,可以看到题目中说数组是有序数组,并且有一句提示很明确:你可以假设 nums 中的所有元素是不重复的。因为一旦有重复元素存在的话,我们使用二分法返回的元素下标可能就不是唯一的了。
因此,当我们在看到题目中有以上的这些限制条件时,就可以考虑是不是应该用二分法解决的时候了
问题
在写二分法时,困扰我最大的其实就是关于left<right 还是left<= right,以及left=middle+1还是middle这种问题。
关于区间的写法有两种,一种是两头闭,一种是左闭右开,这两种是比较大众的,假如我们写左闭右闭的区间,也就是[left, right],那么规则就如下了
- while (left <= right) 要使用 <= ,因为这里left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为这里这个nums[middle]一定不是target,那么接下来要查找的左区间结束的下标位置就是 middle - 1
那么假如我们写的是左闭右开的区间,也就是[left, right) ,那么规则就变成了下面这样
- while (left < right),这里使用 < ,因为这里left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right 赋值为 middle,因为这里nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
经过以上的学习,就可以独立写出下面的代码啦
class Solution {
public int search(int[] nums, int target) {
int left=0,right=nums.length-1;
while(left<=right){
int middle=(left+right)/2;
if(nums[middle]>target){
right=middle-1;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;
}
}
可以看到大大减少了用时
这道题理解了二分查找的思路后,问题就迎刃而解了,没有涉及到java高级语法,所以今天没有学到语法,但是收获了算法,也是不小的收获。