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值;最后一个就是深化递归的思想,递归要有终止条件和子问题的解法。
总结
有什么可以总结的吗?有,不过都在文中了。