总和最大区间问题
给定一个实数序列,长度为K,设计一个最有效的算法,找到一个总和最大的区间。
法一:做三次循环
max:记录最大值。
r:记录右边界。
p从1到K,q从p到K,再循环把p到q加起来。
法二:对重复的循环优化
i:当前位置
使用变量sum记录p到i的和,即变为二重循环。
法三:分治
把序列分为[1,k/2],[k/2+1,k]分别求总和最大的区间。
如果区间之间没有间隔,则总的总和最大区间为[p,q]
如果区间之间有间隔,则最大区间可能为[p1,q1],[p2,q2],[p1,q2],计算[p1,q2]的值,取max([p1,q1],[p2,q2],[p1,q2])。
法四:正反扫描两次
假定最大区间起始数字为正(从第一个开始判断,如果<=0去除)。
如果max一直大于零,只要遍历到k可以得到右边界。
同理得到左边界。
如果num存在小于零的时候
步骤2′,我们先把左边界固定在第一个大于零的位置,假设为p,然后让q=p,p+1,…,K*,计算S*(p,q),以及到目前为止的最大值Max和达到最大值的右边界r。如果我们算到某一步时,发现S(p,q)<0,这时,我们需要从位置q开始,反向计算Maxb,并且可以确定从第1个数到第q个数之间和最大的区间,我们假定它为[l1,r1],这个区间的和为Max1。
特别值得指出的是,l1其实等于p。为什么呢?如果l1≠p,根据我们对这种情况的假设,S(p,l1−1)≥0,于是就有S(p,r1)=S(p,l1−1)+S(l1,r1)≥S(l1,r1)=Max1,这就与[l1,r1]是到q为止和最大的区间相矛盾了。
步骤3′,我们从q+1开始往后扫描,重复上述过程。先是找到第一个大于0的元素,从那里开始做累加操作,可能在遇到某个q′时,又出现S(q+1,q′)<0的情况了,这时我们得到第二个局部和最大区间[l2,r2],相应的区间之和为Max2。
思考题
Q1.将例题1.3的线性复杂度算法写成伪代码。(难度系数2颗星)
int max;
int num;
int r;
while(){
del
}
for(){
r = i;
num += i;
if(){
max = num;
r++;
}
}
Q2.在一个数组中寻找一个区间,使得区间内的数字之和等于某个事先给定的数字val。
(AB、FB、LK等公司的面试题,后面会解答。(难度系数3颗星))
如果是两数之和可以用哈希表。
时间复杂度为:遍历两次
优化:如果都是正数,先找到小于val的起点,再遍历。
Q3.在一个二维矩阵中,寻找一个矩形的区域,使其中的数字之和达到最大值。
贪心算法
(例题1.3的变种,硅谷公司真实的面试题。(难度系数4颗星))