数组-二分查找

1. 二分查找


/**
 * @author xxx
 * @version 1.0
 * @date today
 * <p>
 * 二分查找
 * <p>
 * 给定一个n个元素有序的(升序)整型数组nums 和一个目标值target  ,写一个函数搜索
 * nums 中的 target,如果目标值存在返回下标,否则返回 -1。
 * <p>
 * 提示:
 * 可以假设 nums 中的所有元素是不重复的。
 * n 将在 [1, 10000]之间。
 * nums 的每个元素都将在 [-9999, 9999]之间
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] nums = {-1, 0, 3, 5, 9, 12};
        int target = 9;

        System.out.println(search1(nums, target));
        System.out.println(search2(nums, target));

    }

    /**
     * 左闭右闭实现
     * @param nums
     * @param target
     * @return
     */
    private static int search1(int[] nums, int target) {
        // 先校验参数
        if (nums == null || nums.length == 0) {
            return -1;
        }
        // 左闭右闭
        int left = 0;
        int right = nums.length - 1;
        int middle = 0;
        while (left <= right) {
            middle = (left + right) / 2;
            // 相等
            if (nums[middle] == target) {
                return middle;
            }
            // 小于
            if (nums[middle] > target) {
                right = middle - 1;
            }else { // 大于
                left = middle + 1;
            }
        }
        return -1;
    }


    /**
     * 左闭右开实现
     * @param nums
     * @param target
     * @return
     */
    private static int search2(int[] nums, int target) {
        // 先校验参数
        if (nums == null || nums.length == 0) {
            return -1;
        }
        // 左闭右开
        int left = 0;
        int right = nums.length;
        int middle = 0;
        while (left < right) {
            middle = (left + right) / 2;
            // 相等
            if (nums[middle] == target) {
                return middle;
            }
            // 小于
            if (nums[middle] > target) {
                right = middle;
            }else { // 大于
                left = middle + 1;
            }
        }
        return -1;
    }
}

2. 二分查找的运用-其他案例:

a. 案例1


/**
 *
 * 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
 *
 */
public class FindElementsFirstAndEnd {
    public static void main(String[] args) {
        int[] nums = {5,7,7,8,10};
        int target = 8;

        int[] result = search(nums, target);
        System.out.println(result[0] + "," + result[1]);

        int[] ints = searchRange(nums, target);
        System.out.println(ints[0] + "," + ints[1]);


    }

    /**
     *  我平时的思路实现: 遍历数组实现
     * @param nums
     * @param target
     * @return
     */
    private static int[] search(int[] nums, int target) {
        int first = -1;
        int end = -1;
        if (nums.length == 0){
            return new int[]{first,end};
        }
        // 遍历数组
        boolean flag = false;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target){
                if (!flag){
                    first = i;
                    end = i;
                    flag = true;
                }else {
                    end = i;
                }
            }
        }
        return  new int[]{first,end};
    }

    /** 二分查找,寻找target的右边界(不包括target)
     *
     * @param target
     * @return
     */
    static int[] searchRange(int[] nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        // 情况一
        if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
        // 情况三
        if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
        // 情况二
        return new int[]{-1, -1};
    }

    static int getRightBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }

    static int getLeftBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
}
b. 案例2

/**
 *
 * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
 * 可以假设数组中无重复元素。
 */
public class SearchInsertionLocation {
    public static void main(String[] args) {

        int[] nums = {1,3,5,6};
        int target1 = 5;
        int target2 = 2;
        int target3 = 7;
        int target4 = 0;

        // 调用方法并打印结果
        System.out.println("目标值 5 的索引是:" + searchOfDichotomy2(nums, target1));
        System.out.println("目标值 2 的索引是:" + searchOfDichotomy2(nums, target2));
        System.out.println("目标值 2 的索引是:" + searchOfDichotomy2(nums, target3));
        System.out.println("目标值 0 的索引是:" + searchOfDichotomy2(nums, target4));

    }

    /**
     *  暴力破解法
     *
     * @param nums
     * @param target
     * @return
     */
    private static int searchInsert(int[] nums, int target) {
        // 校验参数
        if (nums.length == 0){
            return 0;
        }
        // 循环
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] >= target){
                return i;
            }
        }
        return nums.length;
    }

    /**
     * 使用二分法处理[左闭右闭]
     *
     * @param nums
     *  @param target
     * @return
     */
    private static int searchOfDichotomy1(int[] nums, int target) {
        if (nums.length == 0){
            return 0;
        }
        int left = 0;
        int right = nums.length - 1;
        int middle = 0;
        while (left <= right){
            middle = (left +right)/2;
            if (nums[middle] == target){
                return middle;
            }else if (nums[middle] < target){
                left = middle + 1;
            }else {
                right = middle - 1;
            }
        }
        return right +1;

    }


    /**
     * 使用二分法处理[左闭右开)
     *
     * @param nums
     *  @param target
     * @return
     */
    private static int searchOfDichotomy2(int[] nums, int target) {
        if (nums.length == 0){
            return 0;
        }
        int left = 0;
        int right =  nums.length;
        int middle = 0;
        while (left < right){
            middle = (left +right)/2;
            if (nums[middle] == target){
                return middle;
            }
            else if (nums[middle] < target){
                left = middle + 1;
            }else {
                right = middle;
            }
        }
        return right;
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值