二分查找

分若干堆糖果给k个孩子,每堆糖果可以再拆分,但无法执行合并工作,问分给k个孩子每人一堆相同糖果数量的最大值。[1]结果在[0,一堆糖果的最大值n]之间取值,用二分查找的方法查找答案。left=0, right=n, 判断条件是按每个孩子一堆mid颗糖果的规则分配,若能分配给不小于k个孩子,说明mid不算太大,res=mid,left=mid+1,,否则说明mid得小点可以分配给更多孩子,right=mid-1,二分查找的循环终止条件是left<=right,res即结果

一个严格递增数组在某位置分为两半,前一半拼接到后一半后面,求在O(logn)时间复杂度下找到某元素在拼接后数组的位置。[2],low=0,high=nums.size(),while(high-low>=1){if(high-low==1){比较low位元素和target;break;}else{找中间值,如果左半边有序,看target是否在那范围内,如果target不再有序范围内,可能在右半边,右半边同理}

n+1长度的数组nums中的元素取值范围1<=num<=n,若其中有一个重复多次的元素,其他元素均只出现一次,问重复多次的元素是。[3]
方法一:二分查找。设cnt[i]表示nums中小于等于i的元素个数,则当i<target时,cnt[i]<=i,当i>=target时,cnt[i]>i。二分查找[1,n]范围的目标值,满足cnt[i]>i的最小值。
方法二:位操作。设y表示nums中数字的每一位的和,x表示1-n数字的每一位的和,若target的那一位是1,则y>x,若target的那一位是0,则y<=x,据此构建target.
方法三:快慢指针,判断图里的环。在索引和元素值间构造图,0到n的索引指向1到n的某一元素值,有向边:i->nums[i],每个点的出度为1,则从0出发,一定会遇到环的入口,因为n+1个点最多n条边会成无环图,再加一条边一定会成环,0无法指向它自己,0诱出一个点,下一个点再诱出一个点,点的诱出总有极限,总有一个点要指向已出现过的点,构成环,且已出现的点的入度为2或以上,就是target。设0到环的入口距离为a,快指针走两跳,慢指针走一跳,快指针率先进入环,慢指针会与快指针在环上的A点相遇,设从环的入口到A距离为b,从A到环的入口的距离为c,则在A点相遇时,慢指针走了a+b远,快指针走了2(a+b)远,快指针也可以是先到A点后转了k圈环,设环长为L,慢指针一定会与快指针在慢指针转环的第一圈里相遇,因为慢指针走一圈,快指针走两圈,肯定相遇。则有2(a+b)=a+b+kL,则a=kL-b。相遇后慢指针回到0点,快指针和慢指针继续一跳一跳地走,当慢指针走a步后,快指针b+a=kL到达相比环的入口kL步的位置,即快指针和慢指针都在环的入口,环的入口就是target.经过上述分析,构建的图具有数字6的笔画的结构。快指针和慢指针相遇的时候,他们的点的值是相等的。

参考链接:[1].5219. 每个小孩最多能分到多少糖果
[2].33. 搜索旋转排序数组
[3].287. 寻找重复数

创建于2022.4.4/13.12,修改于2022.9.14/14.17

#binary_search