leetcode 704 Java二分查找的三种解法

题目

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


相信所有科班的同学对二分查找肯定不陌生,说起来有三种解法,本质上来讲是两种,方法一和方法二是本质上都是递归解法,比较简单,但确实是细节比较多。

方法一:Java的Arrays.binarySearch()

可以直接使用Java中的API解决,只不过Java中的API需要手动处理一下结果。JavaAPI如下:

在这里插入图片描述

注意一下返回值,按照本题来讲,如果找不到的话,直接返回-1,但是在API中返回的不是-1。比如在数组[1,4,2,6,11,32]中,经过排序之后[1,2,4,5,11,32],如果查找13,它会直接返回-6,解释为:从第一个元素之前标为-1,直到第一个大于target数字的元素之前为止,返回负值。可以详细查看下API中的描述,描述中的插入位置很奇妙,其实就跟集合中的remove的API一样,在删除元素之前进行操作。

当然,也可以查看下binarySearch的源码,里面的/2操作也是可以值得借鉴的。

int mid = (low + high) >>> 1;

代码:

package com.yamon.test;

import java.util.Arrays;
public class Search {

    public int search(int[] nums, int target) {
        int binarySearch = Arrays.binarySearch(nums, target);
        if (binarySearch<0){
            return -1;
        }else{
            return binarySearch;
        }
    }

    public static void main(String[] args) {
        int[] arr = {1,2,4,5,11,32};
        System.out.println(Arrays.binarySearch(arr, 13));
//        System.out.println(new Search().search(arr, 13));
    }
}

方法二:迭代处理

标准的迭代操作:

package com.yamon.test;
import java.util.Arrays;
public class Search2 {
    public int search(int[] nums, int target) {
        int low = 0;
        int high=nums.length-1;  //注意这里

        while (low<=high){   //还有这里 要小于等于,要不然会报数组越界异常。
            int mid = low+(high-low)>>1;
            if (nums[mid] == target){
                return mid;
            }else if (target>nums[mid]){
                low = mid +1;
            }else {
                high= mid-1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {-1,0,3,5,9,12};

        System.out.println(new Search2().search(arr, 3));

    }
}

没什么可讲的,就是细节比较多。

方法三:递归处理

到现在,递归给我的感觉其实也就是for循环或者while循环,只不过用空间来换时间了而已。仔细体会下,尤其是注意一下low和high的变化,是不是跟while或者for循环里面类似。

package com.yamon.test;
public class Search3 {
    public int search(int[] nums, int target) {
        return backtrack(0, nums.length - 1, nums, target);
    }
    private int backtrack(int low, int high, int[] nums, int target) {
        if (low > high) return -1;
        int mid = low + ((high - low) >> 1);
        if (nums[mid] == target) {
            return mid;
        }
        if (target > nums[mid]) {
            return backtrack(mid + 1, high, nums, target);
        }
        if (target < nums[mid]){
            return backtrack(low, mid - 1, nums, target);
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] arr = {-1, 0, 3, 5, 9, 12};
        System.out.println(new Search3().search(arr, 9));
    }
}

说一下我存在的问题:将递归看成一个循环的问题,循环的是问题的子问题,那么就不用再在子问题(递归函数)里面用循环了;既然是个子问题,那么必然有return值,在这里的话每个if中要有return值;最后一个就是深化递归的思想,递归要有终止条件和子问题的解法。

总结

有什么可以总结的吗?有,不过都在文中了。

 posted on 2021-06-15 16:57  ben跑的换行符  阅读(101)  评论(0编辑  收藏  举报