Binary Search 二分查找

来源:互联网 发布:2016淘宝市场数据分析 编辑:程序博客网 时间:2024/04/28 19:52

Binary Search 二分查找

有序数组中(允许重复数字),查找第一个最后一个目标数字。时间复杂度为O(logN)。如果需要优化O(n)的时间复杂度,那么只能是O(logn)的二分法。

基本模板:

0. 查找一个(原始方法)

private static int bs(int[] nums, int target) {int start = 0;int end = nums.length - 1;int mid;while (start <= end) {mid = start + ((end - start) >> 1);if (target < nums[mid]) {end = mid - 1;} else if (target > nums[mid]) {start = mid + 1;} else {return mid;}}return -1;}

1. 查找第一个

循环方法:

public static int firstBS(int[] nums, int target) {if (nums == null || nums.length == 0) {return -1;}int start = 0;int end = nums.length - 1;int mid;while (start + 1 < end) {mid = (start + ((end - start) >> 1));if (target < nums[mid]) {end = mid;} else if (target > nums[mid]) {start = mid;} else {end = mid;}}if (nums[start] == target) {return start;} else if (nums[end] == target) {return end;} else {return -1;}}

递归方法:

public static int firstBS(int[] nums, int target, int start, int end) {if (nums == null || nums.length == 0) {return -1;}if (start + 1 < end) {int mid = start + ((end - start) >> 1);if (target < nums[mid]) {return firstBS(nums, target, start, mid);} else if (target > nums[mid]) {return firstBS(nums, target, mid, end);} else {return firstBS(nums, target, start, mid);}} else {if (nums[start] == target) {return start;} else if (nums[end] == target) {return end;} else {return -1;}}}

2. 查找最后一个

循环方法:

public static int lastBS(int[] nums, int target) {if (nums == null || nums.length == 0) {return -1 ;}int start = 0;int end = nums.length - 1;int mid;while (start + 1 < end) {mid = (start + ((end - start) >> 1));<span style="white-space:pre"></span>if (target < nums[mid]) {end = mid;} else if (target > nums[mid]) {start = mid;} else {start = mid;}}if (nums[end] == target) {return end;} else if (nums[start] == target) {return start;} else {return -1;<span style="white-space:pre"></span>}}


递归方法:

public static int lastBS(int[] nums, int target, int start, int end) {if (nums == null || nums.length == 0) {return -1;}if (start + 1 < end) {int mid = start + ((end - start) >> 1);if (target < nums[mid]) {return lastBS(nums, target, start, mid);} else if (target > nums[mid]) {return lastBS(nums, target, mid, end);} else {return lastBS(nums, target, mid, end);}} else {if (nums[end] == target) {return end;} else if (nums[start] == target) {return start;} else {return -1;}}}


总结:

1. 循环方法和递归方法结构上类似:

  1. 判断边界条件
  2. 判断 start + 1 < end
  3. 如果 target < nums[mid],则 end = mid。 慎重使用 end = mid - 1
  4. 如果 target > nums[mid],则 start = mid。慎重使用 start = mid + 1
  5. 如果 target == nums[mid],找第一个 end = mid ;找最后一个 start = mid。这一步可以和上面合并在一起。
  6. 判断 nums[start] nums[end] 是否是要找的目标数字。找第一个先判断 nums[start],找最后一个先判断 nums[end] 
2. 终止条件是 start 与 end 相邻。使用加减1时,start 和 mid 会重合,不好。
3. 计算 mid 时,使用 mid = (start + ((end - start) >> 1)) 可以防止 start + end 溢出。
4. 循环方法 mid 声明在 while循环外。如果只要找mid,则用break跳出循环。循环外要有return。
5. index 在加减1的时候考虑溢出。
6. 二分法的核心在于排除另一半。
7. 注意数组是否能保持有序,是否允许重复。无序数组只能遍历查找。
8. 旋转数组有特别的性质,两段都单调递增,第一段比第二段高,转点是最小值。用二分查找时关键在于排除另一半。

题目汇总:

1. Binary Search   查找第一个目标数字

2. Search Insert Position   查找第一个目标数字,最后根据位置判断。

3. Search for a Range   查找第一个和最后一个目标数字。

4. Search in Rotated Sorted Array 在旋转数组中找到目标数字,画图分析,二分排除。

5. Search in Rotated Sorted Array II 在含重复数字的旋转数组中找目标数字,无法基于二分查找进行优化,数组可看为无序,{2,2,3,2,2}, {3,2,2,2,3}。遍历查找即可。

6. Find Minimum in Rotated Sorted Array 在旋转数组中找到最小值,画图分析,二分排除,将转折点缩小范围到start 和 end。或者暴力求解。

7. Find Minimum in Rotated Sorted Array II 在含重复数字的旋转数组中找目标数字,无法基于二分查找进行优化,数组可看为无序。遍历查找即可。

8. First Bad Version 在boolean有序数组中找到第一个true,直接二分查找即可。

9. Find Peak Element 在多旋转数组中找一个波峰,只找mid,不用加减1。循环外要return。

10. Search a 2D Matrix 在矩阵中搜索目标数字。可以用多行二分搜索。或者右上角/左下角搜索。

11.  Search a 2D Matrix II 在矩阵中搜索目标数字的出现次数。可以用多行二分搜索。或者右上角/左下角搜索。

12. Sqrt(X) 求平方根。用二分搜索。注意乘法会溢出,改用除法。

13. Median of two Sorted Arrays 根据两个数组,求中位数。二分排除法。

0 0
原创粉丝点击