LeetCode刷题踩坑记录——二分查找

LeetCode刷题踩坑记录——二分查找_第1张图片
二分查找使用的前提:数组为有序数组数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。
题目分析略,直接上坑!
先贴代码:

public int search(int[] nums, int target) {
        if(target < nums[0] || target > nums[nums.length-1]){
            return -1;
        }
        int left = 0;
        int right = nums.length-1;
        int middle;
        while(left <= right){
            middle = left + ((right - left) >> 1);
            if(nums[middle] < target){
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle - 1;
            }else{
            	return middle;
            }
        }
        return -1;
    }

模糊点1:计算middle时“middle = left + ((right - left) >> 1);”
右移运算符">>",运算结果是一个整数的二分之一值,这就正好能替代数学上的除2运算,但是比除2运算要快。
(right - left) >> 1 等价于 (right - left) / 2

java中有三种移位运算符
“<< ” : 左移运算符,num << 1,相当于num乘以2
“>>” : 右移运算符,num >> 1,相当于num除以2
“>>>” : 无符号右移,忽略符号位,空位都以0补齐
r = e1 >> e2;
r = e1 >>> e2;
表示把数e1向右移动e2位。(左移类似)
运算规则:
*>> :按二进制形式把所有的数字向右移动对应位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1。符号位不变。
*>>>:按二进制形式把所有的数字向右移动对应位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。
例子,-1在32位二进制中表示为:
11111111 11111111 11111111 11111111
-1>>1:按位右移,符号位不变,仍旧得到
11111111 11111111 11111111 11111111
因此值仍为-1
而-1>>>1的结果为 01111111 11111111 11111111 11111111

错误点1:middle = left + (right - left) / 2 和 middle = (left + right) / 2 的 区别

错误:middle = (left + right) / 2 提交超时(bug)
原因:middle = (left + right) / 2 容易溢出,left+right的值很容易超过int范围
解决方案:middle = left + (right - left) / 2 不容易溢出
middle = left + ((right - left) >> 1) 与 middle = left + (right - left) / 2等价
易错点:区间定义
本文代码给出的是:定义target是在一个左闭右闭的区间里,也就是 “[left,right]”(这个非常容易出错也非常重要)。
区间的定义就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
  • if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

你可能感兴趣的:(LeetCode,leetcode,算法)