今天重要的知识点是看了二分查找,需要掌握的是正确的发现题目中的二分查找的思想。
二分查找的用到的地方 判断有序数组中是否存在某一个数字 求最小值就是左查询,求最大值右查询。
基本模板
int binarySearch(int[] nums, int target) {
int left = 0;
int 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;
}
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
// 当找到 target 时,收缩右侧边界
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
return left;
}
经典的搜索左边界的问题, 找到相的时候,right=mid,继续向左进行搜索。
简单花间一下 就是 nums[mid]>=target的时候right=mid,向左进行搜索。同理向右进行搜索不再展示出来。
我自己的模板
public class test {
public static void main(String[] args) {
int arr[] = {3, 6, 7, 11};
int left=0,right=arr.length;
Scanner scanner =new Scanner(System.in);
int target=scanner.nextInt();
//这是左闭右开的场景
//寻找右侧的
while (left<right){
int mid=left+(right-left)/2;
if (arr[mid]<=target){
left=mid+1;
}else {
right=mid;
}
}
if (left<0||left>arr.length){
System.out.println(-1);
System.exit(0);
}
System.out.println(left-1);
}
}
二分经典题目
leetcode 1011
在传送带上面包裹必须在days天内从一个港口运送到另一个港口,
给出包裹的质量,包裹是依次运出的,给出天数,在这些天内都运出去,
返回days天内将传送带上所有包裹去拿不运出去的最低能力
class Solution {
public int shipWithinDays(int[] weights, int days) {
//运输 涉及到赵左边的最小值或者右边的最大值问题,都可以采用二分查找来解决
//二分 letf 和right是如何确定的呢?
//days天运出,最多一天,最迟每天云一趟,那么最大承载量就是所有的和
// 最小的承载力就是最大的包裹的质量
int left=Arrays.stream(weights).max().getAsInt();
int right=Arrays.stream(weights).sum(); //求得和
while (left<right){
//往左搜索
int mid =left+(right-left)/2;
if (isC(weights,days,mid)) {
//运的比较多了,我们要往小的进行寻找
right=mid;
}else{
//每天云的太少了
left=mid+1;
}
}
//不断的往左进行搜索的,结束的条件是left=right
return right;
}
public static boolean isC(int weights[],int Days,int H){
//如何判断呢
int count=1; //记录当前的天数
int leiji=0;
for (int i = 0; i < weights.length; i++) {
leiji+=weights[i];
if (leiji>H){
count++;
leiji=weights[i];
}
if (count>Days){
return false;//运载量是现实太小了根部运输不了
}
}
return true;
}
}
leetcode 875
有n堆香蕉,存在数组里面了,i下标对应的索引就是多少跟香蕉,警卫离开了,将在h小时后回来。
珂珂决定他吃香蕉的速度,一个小时吃掉k跟,如果这堆香蕉小于k跟,那么就直接吃掉,现在求h小时内吃掉所有香蕉的最小速度
//你可以一个小时内吃掉所有的香蕉,也可以旋转慢慢吃香蕉
确定边界 left是左边界,每个小时必须吃1个
right是右边界,每个小时最多全部吃完
这是第一版写的答案,没有处理好时间关系
int left=1;//不太好确定左边界
int right= Arrays.stream(piles).max().getAsInt();
//因为一个小时吃完,那么最快就吃一堆
//向左进行搜索的
while(left<right){
int mid=left+(right-left)/2;
if (isS(piles,h,mid)){
//符合的话,是向左进行逼近的
right=mid; //不断的向左进行收缩 这个速度是可以直接吃完的
}else {
left=mid+1;
}
}
return left;
}
public static boolean isS(int []piles,int h,int speed){
//如何判断是否满足呢?
//每一个小时吃一推,多了就不吃了
int time=1;
for (int i = 0; i < piles.length; i++) {
int temp=0;
//这是这一推的东西
time++;
temp=piles[i]-speed;
while (piles[i]>speed) {
time++;
//ear>s,ear-s第一次吃完,ear-s-s第二次吃完,
//下一次就再减去
temp=temp-speed;
if (temp<=0){
break;
}
}
//时间边了,就返回false
if (time>h){
return false;
}
}
return true;
}
//正确处理时间关系
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int right=Arrays.stream(piles).max().getAsInt();
int left=1;
while (left<right){
int mid =left+(right-left)/2;
int costTime=0;
for (int pile:piles){
int currentTime=pile/mid;
if (mid*currentTime<pile){
currentTime++;
}
costTime+=currentTime;
}
if (costTime<=h){
//比给定的时间小,要继续向左搜索
right=mid;
}else{
left=mid+1;
//说明比时间大,速度要加快了
}
}
return left;
}
}
leetcode 410分割数组的最大值
本子都是向左进行搜索的
class Solution {
public int splitArray(int[] nums, int k) {
int right= Arrays.stream(nums).sum();
int left=right/k;
//先将连个数组进行分割,找出他们的最大值,但是要求最大值里面的最小值,一眼就是向右搜索
//right 将数组分为一组 。left平均分为k组最大值
// 因为你你不管怎么分,最大值一定是大于平均值的
while (left<right){
int mid =left+(right-left)/2;
if (check(nums,k,mid)){
//向左探索的
right=mid;
}else {
left=mid+1;
}
}
return left;
}
public static boolean check(int []nums,int m,int sum){
int part=1; //初始为一个子数组
int tempsum=0;
for (int num:nums){
if (num>sum){
return false; //如果硬件有一个数比要求的sum大了,直接返回false
}
if (tempsum+num>sum){ //一个子数组放不下了
part++;
if (part>m){
return false;
}
tempsum=num;
}else{
tempsum+=num;
}
}
return part<=m;
}
}