【二分查找】
文章目录
- 1. 二分查找理解
- 2. 题目练习
- 2.1 LeetCode 704 二分查找
- 2.2 LeetCode 35 搜索插入位置
- 2.3 LeetCode 34 找出开始位置和结束位置。
- 2.4 LeetCode 69 X的平方根
- 2.4 LeetCode 367 完全平方数
1. 二分查找理解
使用二分查找的前提是数组是有序的
推荐灵茶山艾府的视频:视频跳转
本文主要考虑的是闭区间的情况
开区间和闭区间最大的差别是初始left和right的取值和while循环的条件;
闭区间:left = 0,right = nums.length-1;
左闭右开:left = 0,right = nums.length;
开区间:left = -1,right = nums.length;
对于left和right的区间变化,时刻记住已经访问过的数组位置不要再次进行判断和访问
import java.util.List;
public class BinarySearch {public static int lower_bound(List<Integer> nums, int target) {int left = 0;int right = nums.size() - 1; // 闭区间 [left, right]while (left <= right) { // 区间不为空int mid = left + (right - left) / 2; // 防止溢出,等同于 (left + right) / 2if (nums.get(mid) < target) {left = mid + 1; // 下一轮搜索区间变为 [mid+1, right]} else {right = mid - 1; // 下一轮搜索区间变为 [left, mid-1]}}return left;// 按照这里的书写情况,是因为当left>right的时候会跳出循环,然而什么时候left会大于right,此时一定是找到了目标值或者数组中不存在这个目标值// 如果是找到了目标值,此时的left就是目标值的位置// 如果是不存在目标值,此时的left就是应该插入的位置}public static int lower_bound(int[] nums, int target) {// 如果存在目标值则输出索引位置,如果不存在目标值则输出-1;int left = 0;int right = nums.length - 1; // 闭区间 [left, right]while (left <= right) { // 区间不为空int mid = left + (right - left) / 2; // 防止溢出if (nums[mid] == target) {return mid;} else if (nums[mid] < target) {left = mid + 1; // 下一轮搜索区间变为 [mid+1, right]} else {right = mid - 1; // 下一轮搜索区间变为 [left, mid-1]}}return -1;}// 如果使用数组而不是List的版本public static int lower_bound1(int[] nums, int target) {int left = 0;int right = nums.length - 1; // 闭区间 [left, right]while (left <= right) { // 区间不为空int mid = left + (right - left) / 2; // 防止溢出if (nums[mid] < target) {left = mid + 1; // 下一轮搜索区间变为 [mid+1, right]} else {right = mid - 1; // 下一轮搜索区间变为 [left, mid-1]}}return left;}// 使用示例public static void main(String[] args) {// 使用List的示例List<Integer> numsList = List.of(1, 2, 4, 4, 5, 6);int target = 8;int result = lower_bound(numsList, target);System.out.println("Lower bound index: " + result); // 输出: 2// 使用数组的示例int[] numsArray = {1, 2, 4, 4, 5, 6};result = lower_bound(numsArray, target);System.out.println("Lower bound index: " + result); // 输出: 2}
}
2. 题目练习
2.1 LeetCode 704 二分查找
LeetCode704
最简单的二分查找的代码
class Solution {public int search(int[] nums, int target) {int left = 0;int right = nums.length-1;while(left<=right){int mid = (left+right)/2;if(nums[mid]==target){return mid;}if(nums[mid]<target){left = mid+1;}else{right = mid-1;}}return -1;}
}
2.2 LeetCode 35 搜索插入位置
题目链接
参考视频中的解法,使得left>right的情况下退出循环,此时的left就是应该插入的位置
class Solution {public int searchInsert(int[] nums, int target) {int left = 0;int right = nums.length-1;while(left<=right){int mid = (left+right)/2;if(nums[mid]==target){return mid;}if(nums[mid]<target){left = mid+1;}else{right = mid-1;}}return left;}
}
2.3 LeetCode 34 找出开始位置和结束位置。
题目链接
start:因为left传输的要么是目标值所在位置,要么是应该插入的位置,所以判断start不存在的情况就是考虑是不是应该插入的位置或者是数组长度,数组长度也是应该插入的位置,但是nums[nums.length]这个数值在数组中不存在,所以start不存的情况需要有两种判断情况
end:同理可得,因为要查找最后一个目标值的位置,相当于寻找 目标值+1 索引位置的前面一个位置,或者是 目标值+1 应该插入的位置的前面一位,比如 [1,2,4,4,8] ,如果我要查找 5 的位置,按照代码会输出 4,即 5 不存在的时候应该插入的位置,而 5 的前面就是最后一个4所在的位置
[1,2,4,4,5,8],如果查找 5 的位置,此时存在 5,输出的left就是 5 在的位置,所以 5 的前一位就是最后一个 4 所在的位置
class Solution {public int lower_bound(int[] nums, int target){int left = 0;int right = nums.length-1;while(left<=right){int mid = (left+right)/2;if(nums[mid]<target){left = mid+1;}else{right = mid-1;}}return left;}public int[] searchRange(int[] nums, int target) {int start = lower_bound(nums,target);if(start == nums.length || nums[start] != target){int[] num = {-1,-1};return num;//不存在start}int end = lower_bound(nums,target+1)-1;int[] res = {start,end};return res;}
}
2.4 LeetCode 69 X的平方根
题目链接
主要是需要理解一下ans = mid这个候选值的情况,因为找的是最大的整数,当left>right 的时候就说明退出循环找到了候选值
而且要注意转变成long型
class Solution {public int mySqrt(int x) {if(x<=1){return x;}int ans = -1;int left = 0;int right = x;// while(left<=right){// int mid = (left+right)/2;// if((long)mid*mid == x){// return mid;// }else if((long)mid*mid<x){// ans = mid;// left = mid+1;// }else{// right = mid-1;// }// }// return ans;while(left<=right){int mid = (left+right)/2;long s_mid = (long)mid*mid;long s1_mid = (long)(mid+1)*(mid+1);if((long)s_mid == x){return mid;}else if((long)s1_mid == x){//其实这个判断可以不考虑,后面会有mid+1return mid+1;}else if(s_mid<x){left = mid+1;// 继续搜索更大的值ans = mid;//记录当前满足条件的候选值,以确保最终返回的是最大的整数 mid}else{right = mid-1;// 搜索更小的值}}return ans;}}
2.4 LeetCode 367 完全平方数
题目链接
class Solution {public boolean isPerfectSquare(int num) {int l=0;int r=num;int ans = -1;while(l<=r){int mid = (l+r)/2;if((long)mid*mid == num){ans = mid;return true;}else if((long)mid*mid<num){l = mid+1;}else{r = mid-1;}}return false;}
}