《编程珠玑》的第8章给出了计算子数组最大和的4种方法:枚举算法,结果保存,分治算法,动态规划算法。
下面是后面给出的两个课后题,觉得有意思,下面说说这个:
第10题:假设我们想要查询的是总和最接近0的子向量,而不是具有最大总和的子向量,你能设计出什么高效的算法,可以采用哪些算法设计的技术?如果我们希望查找总和接近于某个常数t的子向量,结果又将怎么样?
这个问题和第四种动态规划采取的算法思想差不多,也是假设求出了maxendinghere.不过这个时候表示的以i结尾的离0最近的子数组之和。那么这个时候假设计算出了maxendinghere为以i-1为结尾的距离0最近的子数组之和,为了计算以i为结尾的最接近0的子数组,需要分4种情况进行讨论:
第一种情况:maxendinghere为负,a[i]为正数,那么这个时候两者位于原点的两侧,则当abs(a[i])<=abs(maxendinghere+a[i])是,以i结尾的最接近于0的子数组为abs(a[i]),否则为后者
第二种情况:两者均为负,则在坐标原点的同侧,则越加越大,离原点也是越来越远,从而maxendinghere为a[i]本身
第三种情况:两者均为正,则和上述的第二种情况相同,也是maxendinghere为a[i]本身
第四种情况: maxendinghere为正,a[i]为负,和第一种情况是一样的结论。
#include <iostream>
#include <cmath>
#include <climits>
int main(void)
{
int a[10]={1,-2,3,-2,5,2,6,2,2,3};
int minabsum=INT_MAX;
int minsum=0;
for(int i=0;i<10;i++)
{
if(minsum<=0&&a[i]>=0)
{
if(abs(a[i])<=abs(minsum+a[i]))
minsum=a[i];
else
minsum=a[i]+minsum;
}
else if(minsum<=0&&a[i]<=0)
minsum=a[i];
else if(minsum>0&&a[i]>=0)
minsum=a[i];
else
{
if(abs(a[i])<=abs(minsum+a[i]))
minsum=a[i];
else minsum=minsum+a[i];
}
if(minabsum>abs(minsum))
minabsum=abs(minsum);
}
std::cout<<minabsum<<" ";
std::cin.get();
return 0;
}
下面的第12题和13题,课后有答案或者是在<<编程之美》上有原答案,这里就不再多说了。