二分查找(经典)
思路分析
- 首先确定该数组中间元素的下标
mid = (l+r)/2
- 然后让要查找的目标值与中间值比对
- 如果
targetVal > arr[mid],则说明要查找的值在右边,需要递归向右查询
- 如果
targetVal < arr[mid],则说明要查找的值在左边,需要递归向左查询
- 如果
targetVal == arr[mid],已找到目标值
- 什么时候需要退出递归?
- 找到就结束递归
- 遍历完整个数组都没找到,即
left>right时
图解演示找不到的情况:
代码实现
递归实现1
查找返回一个符合条件的值
BinarySearch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package com.yukinoshita.algorithm.search;
public class BinarySearch { public static void main(String[] args) { int[] arr = {1, 4, 8, 19, 53, 84, 190, 201}; int target = 201; int targetIndex = binarySearch(arr, 0, arr.length - 1, target); if (targetIndex != -1) { System.out.printf("目标值%d的下标为:%d\n", target, targetIndex); } else { System.out.println("找不到该值"); }
}
public static int binarySearch(int[] arr, int left, int right, int target) { int targetIndex = -1; if (left > right) { return targetIndex; }
int mid = left + (right - left) / 2; if (target > arr[mid]) { targetIndex = binarySearch(arr, mid + 1, right, target); } else if(target < arr[mid]) { targetIndex = binarySearch(arr, left, mid - 1, target); }else{ targetIndex = mid; } return targetIndex; } }
|
递归实现2
上述算法实现仅能返回一个符合条件的目标值的下标,下面进行修改
修改思路为:
当二分查找内部进入else语句时,说明已经找了了某个值,后续就是return语句。
所以我们可以在else中:先将mid加入到list中,再向左、右邻近元素查询,若还有目标值就加入,方法返回类型也改为List。
下面是核心部分修改:
方法binarySearch2()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public static ArrayList binarySearch2(int[] arr, int left, int right, int target) { if (left > right) { return new ArrayList<Integer>(); }
int mid = left + (right - left) / 2; if (target > arr[mid]) { return binarySearch2(arr, mid + 1, right, target); } else if (target < arr[mid]) { return binarySearch2(arr, left, mid - 1, target); } else { ArrayList<Integer> resIndexList = new ArrayList<>(); int temp = mid - 1; while (true) { if (temp < 0 || arr[temp] != target) { break; } resIndexList.add(temp); temp--; }
temp = mid + 1; while (true) { if (temp >= arr.length || arr[temp] != target) { break; } resIndexList.add(temp); temp++; } resIndexList.add(mid); return resIndexList; } }
|
非递归实现
BinarySearch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.yukinoshita.algorithm.binarySearchNoRecur;
public class BinarySearchNoRecur { public static void main(String[] args) { int[] arr = {1, 3, 5, 7, 9, 11, 12, 16, 20}; System.out.println("查找下标为:"+binarySearch(arr,11)); }
public static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) return mid; else if (arr[mid] > target) right = mid - 1; else left = mid + 1; } return -1; } }
|