这篇文章上次修改于 408 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

ACM程序课算法笔记8——二分答案

问题一:序列划分

问题描述:

给定n个正整数数组a,将这个序列从左到右划分成m段,使得每段至少有一个数;你需要让数字之和最大的那一段的数字和尽可能的小;求最大和最小的值。

解题思路:

根据题目分析,从正向思路来说,需要考虑如何划分,从而变得复杂。但我们如果有无限制的需求,从暴力的角度来看,能否通过枚举答案来获得结果呢?

如果有了答案,我们可以用贪心的思路,让每个子序列装最多个数的数。

让答案从1开始网上枚举,直到成立即可。以上复杂度为O(N2)

能否优化呢?从题目中可以发现,当中有很多无效的枚举,一旦减少枚举的数量,复杂度就可以降低。

那么我们可以选择二分答案,让答案值的枚举顺序和二分查找一样。此时的复杂度为O(NlogN)

经验:

典型的二分答案题通常有”最小值的最大值“,”最大值的最小值“。

至于为什么它们可以满足,是因为答案符合了满足二分的递增性。

例如上题,如果告诉你数字之和最大为T,那么你可以求出m段,显然随着T的变小,m会单调递增

问题二:Ice Cream Tower

给定n个正整数数组a和一个正整数k

一座高度为k的塔b[1…k]满足: b[1] x 2 <= b[2], b[2] x 2 <= b[3], b[3] x 2 <= b[4] …

你要从中选择一些数来叠很多座高度为k的塔,问最多能叠多少座塔。

解题思路:

依旧是二分答案,只不过不同在于如何验证,对于塔的堆叠,不应该一座一座塔的堆叠,应当对于k座塔,先把每座塔的最顶层放置,再放第二层,再放第三层。一旦不能堆叠,便无法叠。

问题三:第K小的数

给定n个正整数数组a 和 m个正整数数组b; 在n * m个a[i] + b[i] 中,找到第k小的数(不去重);

感想:即使我知道是二分答案,我也不好想出题解,此题提问的方式十分有参考价值,不能把二分答案的线索锁定在最小最大最大最小,f(x)[两个值的关系]的递增性才是更重要的

解题思路:

设f(x) 表示有多少对 i, j 满足 a[i] + b[j] <= x

找到最小的x,满足f(x) >= k;

接下来的思路是如何在已知x的情况下得到有几对。

首先将a, b进行排序。

A:二分法

对于已知x,对于数组a中的元素xa,所以数组b中可以和xa成对的个数就是b中小于等于x - xa。

此时就可以用二分查找b中小于x - xa的个数。

B:尺取法

对于已知x,对于数组a中的元素xa,第一次找到b中满足数的位置,然后在xa变大的过程中,反向扫描满足条件b的个数,时间复杂度更低。