算法学习之二分法查找(java版)
二分法可以帮助我们快速的查找到特定元素
思路
- 从有序数组的中间那一个元素「mid」开始,如果该元素就是我们要查找的特定元素,直接返回,算法结束。如果当前数组的长度为0,则无目标元素,算法结束。否则进入第二步。
- 如果该元素小于我们要寻找的特定元素,那么我们从这个数组的右半边[mid+1,right]继续寻找。如果该元素大于我们要寻找的特定元素,那么我们从这个数组的左半边[left, mid-1]继续寻找。
- 重复步骤1-2。
二分法的框架
// 左闭右闭
int binarySearch(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
}
}
return -1;
}
注意一:mid = left + ( right - left ) / 2
这样计算会更好,可以防止left+right的溢出现象
注意二:right = nums.length - 1
表示在这个框架中为左闭右闭,因此while循环中left<=right
,因此right = mid - 1
。我们也可以用左闭右开来写。
// 左闭右开
int binarySearch(int[] nums, int target) {
int left = 0, right = nums.length; // **
while (left < right) { // **
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // **
}
}
return -1;
}
注意我标出来的三处地方配合使用。
二分法的变数
寻找左侧边界的二分搜索方法
在有序数组中找到第一个数值为target的索引
输入:nums=[2,2,2], target =2
输出:index=0
思路:当nums[mid]==target
时,搜索算法不停止,不停地让right靠近left,直到left==right
时,再判断nums[left]==target
即可。
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[left] == target)
return left;
if (nums[mid == target)
right = mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
寻找右侧边界的二分搜索方法
在有序数组中找到最后数值为target的索引
输入:nums=[2,2,2], target =2
输出:index=2
思路:同左侧边界,我们只需要不断让left靠近right即可。
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[right] == target)
return right;
if (nums[mid] == target)
left = mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
总结
二分查找法相对比较简单,记住框架的同时要把握好开闭区间的问题。
申明:本博文是看了labuladong的算法小抄之后个人的理解以及总结。