天天看点

六六力扣刷题数组之再刷二分法

前言

之前小六六一直觉得自己的算法比较菜,算是一个短板吧,以前刷题也还真是三天打鱼,两天晒网,刷几天,然后就慢慢的不坚持了,所以这次,借助平台的活动,打算慢慢的开始开刷,并且自己还会给刷的题总结下,谈谈自己的一些思考,和自己的思路等等,希望对小伙伴能有所帮助吧,也可以借此机会把自己短板补一补,希望自己能坚持下去呀

数组的文章合集

  • 六六力扣刷题数组之理论基础
  • 六六力扣刷题数组之二分查找

题目

给定一个 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]之间。

思路

这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。

二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 ​

​while(left < right)​

​​ 还是 ​

​while(left <= right)​

​​,到底是​

​right = middle​

​​呢,还是要​

​right = middle - 1​

​呢?

大家写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

二分法的主流套路

二分法的写法共分两种分别是:1.定义target在左闭右闭区间 2.定义target在左闭右开区间。

方法1. 定义target在左闭右闭区间,即[left, right]

1.while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=。

2.if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle – 1。

方法2. 定义target在左闭右开区间,即[left, right)

1.while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的。

2.if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]。

反正大家记住 如果是左闭右闭,那么我们就是 middle - 1, 如果是左闭右开 我们就是mmiddle
[] nums, int target) {
   int left = 0;
        int right = nums.length-1;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid]>target){
                right=mid-1;
            }else
            if (nums[mid]==target){
                return mid;
            }else {
                left=mid+1;
            }
        }
        return -1;      

结束

继续阅读