首先向老师表示歉意,由于误记了截止时间,作业提交迟到了3小时,十分抱歉。
在第一周选课期间,我还没有决定选取该门课程,所以并未出席第一次课,也没有提交课堂作业。于是,我在同学的描述下得知了本次的题目。
本次作业的题目是:最大子数组之和。即在一个数组中求得连续子串和的最大值。
思考这个问题时,我首先想到的是动态规划。但是动态规划更适用于求子串位置的问题,本题目并不要求,所以可以有更简便的解法。如果使用穷举法,时间复杂度为O(n2),而使用动态规划,时间复杂度为O(nlogn)。虽然时间复杂度较小,但是递归算法的空间复杂度将会更高,这并不划算。所以我首选了穷举法来解决这个问题,关键代码如下:
for (i=0;i<n;i++){ for(j=i,ctemp=0;j<n;j++){ ctemp+=t[j]; if(ctemp>max) max=ctemp; } }
这是一个简单的穷举法,从前到后穷举了每一个子串和,最终将最大值输出。
不过这个程序还可以进一步改进。分析问题可以得知,具有最大和的子串的首尾元素不可能是负数。例如,如果是num[i]负数,则存在以num[i+1]为开头的更大子串。同理,以和为负的小子串开头的子串也必然是可以优化的。在网上查阅了一些资料后,我做出了以下优化:
for (j=0; j<=i; j++){ ctemp+=t[j]; if (ctemp>max) max=ctemp; else if (ctemp<0) ctemp=0; }
该段代码是在上一段基础之上的改进。其原理在于,通过排除负开头数字/子串的方式,节约了第一个for循环,从而将复杂度降低至O(n)的线性水平。
不过此时也产生了一个例外情况:输入元素均为负值。那么还要增添一个判断条件,如果元素均为负,则最大子串和等于最大元素的值。
以上为该次作业的全部讨论。
另:我选择的教科书为 中文版 代码大全 (第二版)。