1.8学习博客

今天练习了一些关于二分查找的题目。
第一题:https://leetcode-cn.com/problems/capacity-to-ship-packages-within-d-days/
在这里插入图片描述
在这里插入图片描述
由于本题目中求的是货船的容量,容易知道的是,该容量最小为所有货物重量中的最大值,最大为所有货物重量之和。可以从这个方面来进行二分查找。
部分代码:
int shipWithinDays(int* weights, int weightsSize, int D){
int min=-1,max,sum=0;
max=weights[0];
for(int i=0;i<weightsSize;i++){
sum+=weights[i];
if(max<weights[i])max=weights[i];
}
int left=max,right=sum;
while(left<=right){//二分
int mid=(left+right)/2;
int k=0,day=0;
for(int i=0;i<weightsSize;i++){
k+=weights[i];//超重之前累加
if(k>mid){
day++;
k=weights[i];//将这次的weights[i]当做另起一天拉的货物重量
}
}
day++;//!~!!不能少,出循环之前的那一天
if(day>D){//容量过小,超出时间
left=mid+1;
}
else{//在时间D内
right=mid-1;
if(min==-1)min=mid;//将首次符合要求的mid赋予min
min= mid<min?mid:min;//取符合要求的最小的容量
}
}
return min;
}

第二题:https://leetcode-cn.com/problems/magnetic-force-between-two-balls/
在这里插入图片描述

在这里插入图片描述
借鉴leetcode官方题解和大佬的思考,给定 n 个空篮子,m 个球放置的位置已经确定。那么「最小磁力」我们该如何计算?

不难得出「最小磁力」为这 m 个球中相邻两球距离的最小值的结论。对于i<j<k 三个位置的球,最小磁力一定是j−i 和 k−j 的较小值,而不是跨越了位置 j 的 i 和 k 的差值 k−i。

明确了给定位置最小磁力的计算方法,在本题中 m 个球的位置是由我们决定的,只知道空篮子的位置,且题目希望通过排列 m 个球的位置来「最大化最小磁力」。

我们假定最终的最小磁力为 ans,那么我们知道小于ans 的答案一定也合法。因为既然我们存在一种放置的方法使得相邻小球间距的最小值大于等于 ans,那么也一定大于 [1,ans−1] 中的任意一个值,而大于 ans 的均不合法,因此我们可以对答案进行二分查找。
对于这道题来讲,我们的二分改变的是答案的范围,最终一步步逼近答案。当m = 2的时候,所有球的最小磁力最大距离为容器的头和尾,当m = 3的时候,我们此时能找到的最大距离是容器头减尾除以2,咱们可以自己慢慢往下推,其中的思想就是尽可能均分球的位置。因此我们能够得到每两个球的最大长度就是(position[positionSize-1]-position[0])/(m-1),最小长度当然就是1了。

好,现在我们就能用二分了,我们用二分是为了找均分后的长度,看看哪个符合,要记住这里的二分,分的是可能的长度(介于最小和最大之间)。接下来我们就要验证这个此时我们分出来中间的长度到底能不能成功让球摆放后符合。因此我们要进行验证,也就是对应的check函数。

check函数体里,我们要进行一一验证。验证的思路就是,从最左侧开始,每间隔二分出来的距离然后开始放球,如果此时能放下的数量大于m或者是间隔的数量大于等于m - 1,那么我们此时分出来的距离是可行的,因此再次向右侧进行二分搜索。最终找到分出来的那个距离。

部分代码:
在这里插入图片描述
第三题:https://leetcode-cn.com/problems/kth-smallest-number-in-multiplication-table/
在这里插入图片描述
这道题其实常规思路很简单,但是用二分的话,还是有思考价值的:
借鉴大佬对该题二分的解释
1、找第k小,第k大一类的问题,一般情况下都是用二分来解决,那么二分法就需要到二分的数据点以及比较方式。
2、当前乘法表中最小值肯定是1,最大值为m*n,也就是我们这张表的最小和最大值,数据点找到。
3、比较方式,要找到第k小,那么我们在拿到mid数据点的时候,去看当前mid的位置,如果mid位置大于k,说明mid值太大,需要再次进行二分求解。
4、问题来了,这个位置怎么找呢,假设mid位于指定行i,那么mid/i也就是mid元素的列的位置,如果列的位置大于列最大长度n,那么说明该行所有数据都小于mid,累加n即可。
如果不是呢,说明找到了正确的行,只需要mid/i列的位置也就是这一行小于mid的元素个数。
5、边界条件的处理是二分法中比较重要的,我们要找第k小,那么可以理解为假设当mid处于某个值时,满足了条件,我们需要锁定大值,也就是count>=k,去调整l的值不断逼近。
当l的值逼近到某个数据,使得条件再次满足时,就是循环条件结束的时候,这样可以保证l的值一定是在原列表中的,因为+1或-1都会导致条件不满足。
当然我们的>=条件也是不允许的,因为满足之后l值就被锁定了。

注意:此题是要找第一个满足K的数值,所以就是找左边界。

部分代码:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_47529865/article/details/112370174
1.8