算法通关村第九关——透彻理解二分查找

35 阅读2分钟

青铜挑战:逢试必考的二分查找

1.什么是二分查找?

二分查找就是将数组的中间值和目标值比较,然后排除掉数组一半的元素,在另一半中继续利用中间值和该目标值进行比较,依次类推;前提是给定的数组要有序

对于在一个有序的数组中找出目标值的问题,我们应该要很快想到使用二分查找来解决;

2.如何实现二分查找算法呢?

 /*
  *  使用循环方式来实现
  * */
    public static int binarySearchByCirculation(int[] arr, int low, int high, int target) {
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] > target) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        // 没有找到
        return -1;
    }
​
    /*
     * 利用递归方式来实现
     * */
    public static int binarySearchByRecursion(int[] arr, int low, int high, int target) {
        if (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] > target) {
                return binarySearchByRecursion(arr, low, mid - 1, target);
            } else {
                return binarySearchByRecursion(arr, mid + 1, high, target);
            }
        }
        return -1;
    }
​
​
    public static void main(String[] args) {
        int[] arr = {1, 2, 4, 6, 8, 9};
        int target = 1;
        int res1 = binarySearchByCirculation(arr, 0, arr.length - 1, target);
        int res2 = binarySearchByRecursion(arr, 0, arr.length - 1, target);
        System.out.println(res1 == res2); // 输出true
    }
​

3.二分查找重复元素最左侧元素的下标

解题思路:首先利用二分查找定位到目标值的位置mid,再依次从mid位置向左开始寻找,直到元素不重复为止;

具体实现:

public static int binarySearchLeftEle(int[] arr, int left, int right, int target) {
    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        if (arr[mid] > target) {
            right = mid - 1;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            // 一直向左寻找直到元素不再重复
            while (mid > 0 && arr[mid] == target) mid--;
            // 如果此时mid == 0 并且还是重复元素,直接返回mid即可,也就是0;
            if (mid == 0 && arr[mid] == target) {
                return mid;
            }
            // 表示发现了往左寻找的第一个不重复元素,那么mid向右的一个位置即是重复元素中最左位置;
            return mid + 1;
        }
    }
    return -1;
}