二分答案
需要找一个整数,我们知道它的最小和最大值,用二分法最后找到这个数。
69.X的平方根
1.如果向下 mid=l+(r-l)/2,最后得到的是大于等于x最小的数
如果是向上 mid=l+(r-l)/2+1 才是得到小于等于x最大的数
2.如果判断条件写成:
会发生溢出
需要改成
287.寻找重复数
数组不是有序的。
思路:
在重复数出现之前,小于等于数字i的数肯定小于等于i个。
在重复数出现之后,小于等于数字i的数肯定大于i个。
多的计算量就是要算,小于等于这个数总量有多少(O(n))。
1300.转变数组后最接近目标值的数组和。
先找数组规律。这个value最小为0,因为所有大于0的都会变成0,最后这个数组的和为0。之后是单调递增,value越大,和会越大。当value等于数组中最大的数的时候,value再增加,数组和也不会变了。
所以左边界l=0,右边界r=arr.max。
进行二分查找,结果肯定是要么比目标数大一点,要么比目标数小一点,必然在这两个中间一个。
我们先设置一个ans是在比目标小一点的那个,然后得出后,直接与下一个比较绝对值,最后得出结果。
多余的计算是要每次算value更新后的和。
时间复杂度:
设最大数为C,因此二分查找复杂度为O(log C),每次查找还要遍历数组一次,
O(N log C)
空间复杂度:
O(1)
判别条件复杂的二分查找问题
之前的二分答案,是单调的,因此好判断趋势。但是一些问题中的目标变量不好判断,但是与之相关的另一个变量,所以会用一个判别函数。
875.爱吃香蕉的珂珂
和1300类似。先分析左边界和右边界。左边界为1,也就是至少每小时吃一根。
考虑到H的范围:如果H最小为堆数,那么要保证每一堆都能在一个小时内被吃完。
所以右边界为max(piles)。
我们是用总时间和H比较,S>H,说明速度慢了,K应该在右区间。S<H说明速度快了,K应该在左区间。
值得注意的是,这里有重复值。也就是说也许取4或者5,S值不变。但是我们需要小的那个。因此 S==H时,不忙着退出,而是r–,相当于向左范围靠近。
最后得到的那个数就是最小满足要求的值。
时间复杂度:
O(NlogW) 其中W为数组中最大值,N为数组数
空间复杂度:
O(1)
410. 分割数组的最大值
用二分法。也是先找左右边界。左边界应该为数组中最大的数,右边界是整个数组的和(这种情况m=1)
然后挨个比较,这个数是否能满足分成m份,如果不能满足,取右区间,说明这个数还不够大。如果满足就取左区间,说明我们还可以尝试更小的数。
如何检查该数是否符合分堆要求?
直接数,一旦和大于这个数,那么堆数+1,起始堆为1,找到一个分界点,从一堆变成两堆。
如果堆数比指定堆数多,说明不能满足。如果比指定的少,最大的那个还可以再分,说明可以满足。
时间复杂度:
O(nlog(sum-max))
空间复杂度:
O(1)
1011. 在 D 天内送达包裹的能力
和上面的分割最大数组一模一样的解法。
1482 .制作 m 束花所需的最少天数
取的这个数,小于它的天数都会开花。右区间为数组中最大值,就是整个数组花都开了。左区间取1。
如果满足堆数,那么我们的天数还可以少,否则就是要增加天数。
检查函数是查看是否能形成足够多的连续堆数。数到足够连续数,花束+1,然后枝数归0。
时间复杂:
O(NlogC)
空间:
O(1)
小张的刷题计划
类似分割数组最大值。
左区间为0,都是小杨做题,右区间为数组和
不同的在于check函数,我们有个机会减去最大值。