【数据结构与算法】二分查找法
在开始将二分查找法之间先看一个需求,在一个有序数组中,查找一个目标值,如果该值存在,则返回对应的索引值,否则返回-1(代表没找到)。
比如数组是[1,2,3,5,7,9],查找目标值3所在的索引,这个问题很简单,我们只需要遍历数组判断即可。
public class Solution {
public int search(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] == target) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
System.out.println(new Solution().search(new int[]{1, 2, 3, 5, 7, 9}, 3)); // 2
System.out.println(new Solution().search(new int[]{1, 2, 3, 5, 7, 9}, 0)); // -1
}
}
上面这种算法可以解决问题,但是它并不优秀,最好的情况下,可能第一个元素就是目标值,时间复杂度是O(1),最坏的情况下,可能数组最末尾一个才是目标值,那么就要比较n次,所以最坏的时间复杂度是O(n)。
有没有更优秀的算法呢?答案是有的,比如二分查找法就是其中一种,二分查找法,也叫做二分搜索法,当数组是有序数组的时候,使用二分查找法的时间复杂度是O(logN)。
有序数组是说一个数组中的元素是有序的(升序或者降序),比如
[1, 2, 3, 4, 5, 10],或者[10, 9, 4, 2, 1],特别要说明的是像[10, 10, 9, 8, 4]这样的有重复但是整体有序的数组也是符合条件的!!!
二分查找的精髓体现在二分这两个字上,意思是对数组每次都分成两部分,我以如下数组为例:

如图所示数组被分为左右两部分,被中间值所分开,首先用中间值与目标值进行比较,如果中间值等于目标值,那么说明找到了,如果中间值大于目标值,说明目标值应该是在左半部分,需要向左侧查找,否则向右查找。
那么如何确定左半部分、右半部分、以及中间值呢,肯定得用指针,二分查找法中我们首先要定义两个指针,一个做指针left,一个右指针right,初始的时候left = 0,right = N - 1,mid = (left + right) / 2, 如下图所示:

情况1:
如果target = 7说明正好就找到了,那么mid = 4这个索引就是查找结果。

情况2:
目标值等于3的时候。

通过上面的分析,可以得出二分查找法的算法步骤:
- 设置两个指针
left和right,初始值left = 0, right = N - 1。 - 计算中间索引,计算公式为
mid = (left + right) / 2。 - 如果target = nums[mid],找到了。
- 如果target > nums[mid],则将左指针移动到mid后面的位置,也就是
left = mid + 1,回到第2步,继续计算。 - 如果target < nums[mid],则将右指针移动到mid前面的位置,也就是
right = mid - 1,回到第2步,继续计算。 - 如果
left > right的时候,则停止计算。
代码如下:
class Solution {
public int binarySearch(int[] nums, int target) {
int N = nums.length;
int left = 0;
int right = N - 1;
while (left <= right) {
int mid = (left + right) >>> 1;
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
public static void main(String[] args) {
int[] nums = new int[] { 1, 2, 3, 5, 7, 9, 20, 30, 88 };
System.out.println(new Solution().binarySearch(nums, 3)); // 2
System.out.println(new Solution().binarySearch(nums, 0)); // -1
System.out.println(new Solution().binarySearch(nums, 100)); // -1
int[] nums2 = new int[] { 1, 2, 2, 2, 3, 5, 7, 9, 20, 30, 88 };
System.out.println(new Solution().binarySearch(nums2, 2)); // 2
}
}
本文介绍了在有序数组中查找目标值的简单遍历算法和二分查找法。二分查找法通过每次将数组分为两半,通过比较中间值实现更快的O(logN)时间复杂度,展示了其实现过程和关键步骤。
619

被折叠的 条评论
为什么被折叠?



