编程珠玑习题 - 第八章

第八题:

要求改进分治算法,使其复杂度为O(N)。

既然是分治法,一共有logN层,既然要求复杂度为O(N),那显然程序最后的复杂度应该是O(logN)+O(N)。用动态规划的思想,我们需要花O(N)时间建立两个数组,

before[]和after[]。before[i]表示以第i个元素结尾的最大序列和,after[i]表示以第i个元素开始的最大序列和。建完这个表之后,原来分治法中需要O(N)找到Mc的值,

现在只用O(1)即可获得Mc = before[mid]+after[mid+1]。但是,其实只需要建完before数组后遍历before一次即可找到最大值,因为最大值序列要么是0,要么是以某个元素结尾的序列。 所以我觉得这道题答案如果真是我所想的这样,那无疑是很没有意思的。。但的确是分治法,又的确是O(N)复杂度。

代码如下:

封装在一个类中,init()函数O(N)复杂度,完成before与after的赋值。maxsum3复杂度O(logN),总的复杂度为O(N)+O(logN)。


第十题:

函数equal_zero返回最近接0的子向量之和。

如答案所说,思想是用数组sum[i]记录前i个数字之和,这样任何l,u之间数字之和克表示为sum[u]-sum[i-1]。

O(NlogN)对sum排序,然后遍历查找最近接的相邻元素。

class PearlsCh8{
public:
	PearlsCh8(int num, float *data){
		n = num;
		x = data;
		before = new int[n];
		after = new int[n];
		init();
	}
	void init(){
		before[0] = x[0];
		for(int i=1;i<n;++i)
			before[i] = before[i-1]>0? (before[i-1]+x[i]) : x[i];
		after[n-1] = x[n-1];
		for(int i=n-2;i>=0;--i)
			after[i] = after[i+1]>0? (after[i+1]+x[i]) : x[i];
	}
	float maxsum3(int l, int u){
		if(l > u)
			return 0;
		if(l == u)
			return max(0,x[l]);
		int mid = (l+u)/2;
		return max((before[mid]+after[mid+1]),max(maxsum3(l,mid),maxsum3(mid+1,u)));
	}
	float equal_zero(int l, int u){
		int *sum = new int[n+1];
		sum[0] = 0;
		for(int i=1;i<=n;++i)
			sum[i] = sum[i-1] + x[i];
		sort(sum,sum+n+1);
		float res = x[0];
		for(int i=1;i<=n;++i)
			res = abs(sum[i]-sum[i-1])<abs(res)?(sum[i]-sum[i-1]):res;
		delete[] sum;
		return res;
	}


private:
	int n;
	float *x;
	int *before;
	int *after;
};

int main(){
	float x[] = {31,-41,59,26,-53,58,97,-93,-23,84};
	PearlsCh8 p(10,x);
	cout<<p.maxsum3(0,9)<<endl;
	getchar();
	return 0;
}



第十三题:

data为M*N的矩阵,算法复杂度为O(M^2*N)。

float maxsum(vector<vector<float> >&data){
	int m = data.size();
	int n = data[0].size();
	vector<vector<float> >sum(n+1,vector<float>(m+1));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j)
			sum[i][j] = sum[i][j-1] + data[j-1][i-1];
	}
	float res = data[0][0];
	for(int i=1; i<=m;++i){
		for(int j=i;j<=m;++j){
			float end_cur = sum[1][j]-sum[1][i-1];
			for(int k=2;k<=n;++k){
				end_cur = end_cur>0?(end_cur+sum[k][j]-sum[k][i-1]):(sum[k][j]-sum[k][i-1]);
				res = max(res,end_cur);
			}
		}
	}
	return res;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值