python第三章上机实践报告_算法第三章上机实践报告

算法第三章上机实践报告

组员:高珞洋,何汶珊

实践题目

7-2 最大子段和

给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。

要求算法的时间复杂度为O(n)。

问题描述

由于要求时间复杂度是O(n),因此递归的方法被砍,只能另外谋求生计

当时间复杂度为O(n),第一反应是用一个for循环,但是如何能只用一个for循环得出结果呢?

自然想到在循环遍历的时候将当前最优解存起来,最后进行一个比较,选择最好的那个解

于是就用到动态规划法来解决问题。

算法描述

算法的核心在于递归方程

MaxSum[i] = ele[i] i=0

MaxSUm[i] = max{ele[i], ele[i] + MaxSum[i - 1]} 0 < i < n

因此着重讲解递归方程的求得过程

首先对原输出和辅助记录空间进行定义

ele[i]:序列的第i - 1个元素,i从0开始(数组下标)

MaxSum[i]:从ele[0],以ele[i]为尾数的最大子段和(可能不包括ele[0],ele[1]....ele[i - 1])

然后我们分析最开始的情况,从第一个数开始

第一个数有两种情况,小于等于或0大于0。若小于等于0,则最大子段和必不包括它,因为它是第一个数。如果是大于0,则最大子段和有可能包括它。

然后到第二个数,先不管第二个数的正负,根据上一条,如果第一个数ele[0]大于0,那么序列{ele[0],ele[1]}对应的MaxSum[1]=ele[0]+ele[1];如果ele[0]小于0,对应的MaxSum[1]=ele[1],及最大子段和为本身,因为前面只有一个数还小于0,所以必不要它

再看第三个数,在这时候我们将前面的所有数,不管有多少个(现在是两个),都抽象成“前面的数”,它的值为MaxSum[i-1]。那么我们的第三个数就会变成“前面的数”的后面那个数,也就变成了“第二个数”。那么根据上面第二个数的判断,如果“前面的数”小于0,那么“前面的数”都不要了,其最大子段和为本身;反之,最大子段和为“前面的数”加上本身。

也就是说,当前我们看第i个数ele[i],这个数之前的最大子段和为MaxSum[i - 1],如果MaxSum[i - 1] < 0,那么以ele[i]为尾数的最大子段和MaxSum[i]必为ele[i],否则,其为

为统一,我们将第一个数的最大子段和定义为其本身,即:

MaxSum[0] = ele[0]

注意,这里有个坑,就是以ele[i]结尾的序列,他的最大子段和不一定包括ele[i]。很多在上面的推导过程中都发现了,序列{ele[0],ele[1]}的最大序列可以是ele[0](ele[0]>0, ele[1] < 0)。 而我们MaxSum存的是以ele[i]为尾数的最大子段和,因此MaxSum的最后一个数MaxSum[n]并非最终答案。序列{ele[0],ele[1]...ele[n]}的最大子段和可能为{ele[i],ele[i+1]...ele[j]}(0

因此我们需要额外一个变量来存放MaxSum中的最大值(当然你也可以得到MaxSum后遍历找最大)。

算法时间及空间复杂度

时间复杂度

无非就是循环判断,T(n) = O(n)

空间复杂度

需要一个和原序列等大的辅助空间来记录,S(n) = O(n)

心得体会

动态规划实际上没有很复杂,代码量也非常少。辅助空间的存在省去了很多额外的计算步骤,这是它在计算量和时间程度优于递归的原因之一。

和分治法不同的是,动态规划的子问题不是相互独立的。比如在这道题中,去掉每个序列的最后一个数所得到的新的序列就是一个新的子问题,可以看出他们存在包含的关系。

动态规划法的难点在于求解递归方程,说实话递归方程出来后,代码的编写一气呵成。大部分时间还是花在了分析问题、求解递归方程上。

所以递归方程是利用动态规划法解题的核心。

核心源码

for (int i = 0; i < n; i++) {

if (i == 0) {

maxSum[i] = elements[i];

}

else

{

maxSum[i] = max(elements[i], (elements[i] + maxSum[i - 1]));

}

if (maxSum[i] > maxResult) {

maxResult = maxSum[i]; //maxResult为额外存放MaxSum中最大值的变量

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值