int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while(...) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
无论使用二分搜索是查找单个元素还是搜索边界,最本质的点在于保证搜索区间的合法性
public static int binarySearch(int[] arr,int target){
int left=0,right=arr.length-1;
while (left<=right){
int mid=left+(right-left)/2;
if (arr[mid]==target){
return mid;
}else if (arr[mid]<target){
left=mid+1;
}else if (arr[mid]>target){
right=mid-1;
}
}
return -1;
}
// 递归方式
public static int binarySearch(int[] arr,int target,int left,int right){
if (left>right){
return -1;
}
int mid=left+(right-left)/2;
if (arr[mid]==target){
return mid;
}else if (arr[mid]<target){
return binarySearch(arr,target,mid+1,right);
}else if (arr[mid]>target){
return binarySearch(arr,target,left,mid-1);
}
return -1;
}
// 查找左边界
public static int searchLeft(int[] arr,int target){
int l=0,r=arr.length-1; // [l,r]
// 终止条件l>r
while (l<=r){
int mid= l+(r-l)/2;
if (arr[mid]==target){
// 收缩右边界,锁定左边界
r=mid-1;
}else if (arr[mid]<target){ // mid+-1取决于当前模式是否已经搜索过mid自身
l=mid+1;
}else if (arr[mid]>target){
r=mid-1;
}
}
// target可能极大,导致left一直右移,可能越界
if (l==arr.length){
return -1;
}
// [l,r]=[l,mid-1],此时大概arr[mid]=target,当l>r导致搜索终止时,说明l=mid
return arr[l]==target?l:-1;
}
// 查找右边界
public static int searchRight(int[] arr,int target){
int l=0,r=arr.length-1; // [l,r]
// 终止条件l>r
while (l<=r){
int mid= l+(r-l)/2;
if (arr[mid]==target){
// 收缩左边界,锁定右边界
l=mid+1;
}else if (arr[mid]<target){ // mid+-1取决于当前模式是否已经搜索过mid自身
l=mid+1;
}else if (arr[mid]>target){
r=mid-1;
}
}
// target可能极小,导致right一直左移,可能越界,此时r<0,而l>r -> l=r+1 -> l-1=r,所以r<0可写为l-1<0
if (l-1<0){
return -1;
}
// [l,r]=[mid+1,r],此时大概arr[mid]=target,当l>r导致搜索终止时,说明l-1=mid
return arr[l-1]==target?l-1:-1;
}
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。链接:https://leetcode.cn/problems/binary-search
解题思路:这道题是最原始的在有序数组中查找单个元素的问题,直接使用代码框架即可;
class Solution {
// 二分查找
public int search(int[] nums, int target) {
int l=0,r=nums.length-1; // 搜索区间两端为闭区间
while(l<=r){ // 加等号
int mid=l+(r-l)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]<target){
l=mid+1;
}else if(nums[mid]>target){
r=mid-1;
}
}
return -1;
}
// 线性查找
// public int search(int[] nums, int target) {
// for(int i=0;i
// if(target==nums[i]){
// return i;
// }
// }
// return -1;
// }
}
狒狒喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。狒狒可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉,下一个小时才会开始吃另一堆的香蕉。 狒狒喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
链接:https://leetcode.cn/problems/nZZqjQ/
分析:
解题思路:
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int maxPile=getMaxPile(piles);
int l=1,r=maxPile; // 搜索区间[l,r]
while (l<=r){
int mid=l+(r-l)/2;
if (restBanana(piles,h,mid)){ // 可以吃完,说明速度大于等于最小速度
r=mid-1;
}else if (!restBanana(piles,h,mid)){ // 吃不完,说明速度小于最小速度
l=mid+1;
}
}
if (l>maxPile){
return -1;
}
return l;
}
// 以当前速度在h小时内是否可以吃完
private boolean restBanana(int[] piles, int h, int speed) {
int time=0;
for (int pile:piles){
time+=(pile/speed);
time+=(pile%speed==0?0:1);
}
return time<=h;
}
// 确定最大香蕉堆数量,以此作为有可能的最大速度
public int getMaxPile(int[] piles){
int max=piles[0];
for (int i=1;i<piles.length;i++){
max=Math.max(max,piles[i]);
}
return max;
}
}
代码框架,参考labuladong,https://labuladong.gitee.io/algo