二分查找刷题

98 阅读1分钟

二分查找刷题

704. 二分查找

1.左闭右闭写法

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while(left <= right){
            //mid = (left + right )/2 = left + (right - left)/2,注意!!!位运算的优先级要比+号低
            int mid = left + (right - left) >> 1;
            if(target > nums[mid]) left = mid + 1;
            else if(target < nums[mid]) right = mid - 1;
            else return mid;
        }
        //在循环结束(即left > right时)时还没return,说明没找到
        return -1;
    }
}

2.左闭右开写法(右开值其实等于右闭值再加1,参考那些数组长度循环判断)

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

34. 在排序数组中查找元素的第一个和最后一个位置

思路:因为有序,target在数组中有两种情况:
1.数组中存在target,那么找到的左右边界长度要大于等于1
2.数组中找不到,有三种情况:
  2.1.这个数比区间中任何一个数还小
  2.2.这个数比区间中任何一个数还大
  2.3这个数在左右区间之间,但是不存在,也就是说左右边界的差,要小于等于0

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int leftBound = getLeftBound(nums, target);
        int rightBound = getRightBound(nums, target);
        if(leftBound == -2 || rightBound == -2){
            return new int[]{-1,-1};
        }
        if(rightBound - leftBound > 1){
            return new int[]{leftBound + 1, rightBound - 1};
        }
        return new int[]{-1,-1};
    }

    private int getRightBound(int[] nums, int target){
        int left = 0, right = nums.length - 1;
        int rightBound = -2;
        while(left <= right){
            int mid = left + ((right - left) >> 1);
            if(nums[mid] > target) right = mid - 1;
            else{
                left = mid + 1;
                rightBound = left;
            }
        }
        return rightBound;

    }

    private int getLeftBound(int[] nums, int target){
        int left = 0, right = nums.length - 1;
        int leftBound = -2;
        while(left <= right){
            int mid = left + ((right - left) >> 1);
            if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid - 1;
                leftBound = right;
            }
        }
        return leftBound;

    }
}

69. x 的平方根

本题用二分查找,mid的平方是必须小于等于x的,对比上题,发现本质上就是在求右边界(也就是收缩左区间时)。

class Solution {
    public int mySqrt(int x) {
        int left = 0, right = x, ans = -1;
        while(left <= right){
            int mid = left + ((right - left) >> 1);
            if((long) mid * mid <= x){
                ans = mid;
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return ans;
    }
}

367. 有效的完全平方数

把上面的69题算出的最大算数平方根的方法拿来用就好了

class Solution {
    public boolean isPerfectSquare(int num) {
        int sqrt = sqrt(num);
        return sqrt * sqrt == num;
    }

    private int sqrt(int num){
        int left = 0, right = num, ans = -1;
        while(left <= right){
            int mid = left + ((right - left) >> 1);
            if((long)mid * mid <= num){
                ans = mid;
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return ans;
    }
}