最大二位子数组和问题(homework-02)
前面已经谈过最大一维子数组和问题,这里面扩展到二维。
一. 常规情况,一个矩形的数组,找到一个矩形的子数组有最大的元素和,求这个和。
1. 从朴素算法入手,枚举矩形数组的4个顶点,以此计算其数组和。同样,时间复杂度很大,我们仅以此入手逐步优化。
2. 参照一维数组的思路,保存中间结果,利用动态规划优化算法。优化点就是子数组求和一处,二维数组的求和不同于一维,但是仍然能找到方法:
先声明这个方法是参考《编程之美》书中的讲解的,鄙人大脑迟钝,尚无法独创:
令二维数组的起点不是0,而是1,使用PS[i][j]表示以[0][0], [i][0], [0][j], [i][j]四个顶点围起来的子数组和,边界上的PS[*][0]和PS[0][*]全置零。则有:
PS[i][j] = PS[i - 1][j] + PS[i][j - 1] - PS[i - 1][j - 1] + A[i][j]
其中,A为整个二维数组,Row_num, Clm_num分别为数组行数、列数。
void cal_PS(){ int i, j; for (i = 0; i <= Row_num; i++){ PS[i][0] = 0; } for (j = 0; j <= Clm_num; j++){ PS[0][j] = 0; } for (i = 1; i <= Row_num; i++){ for (j = 1; j <= Clm_num; j++){ PS[i][j] = PS[i - 1][j] + PS[i][j - 1] - PS[i - 1][j - 1] + A[i][j]; } } }
上面的函数处理了部分和,这部分时间复杂度O(Row_num2 * Clm_num2).
3. 有了部分和,下面寻找最大和的数组。我们的核心思路是把未知问题归结到已知的一维问题上。即,首先循环二维子数组数组的上下界,在每个上下界确定的情况下,用一维数组的方 法确定其左右边界。形象一点说,就是先假定数组上下界已知,然后把每一列上的元素压扁,变成一维的。BC(a, c, j)就是a, c两行之间第j列元素加在一起的和。
核心部分如下:
1 int MaxSum_mode1(){ 2 int maximum = -2147483648;// 一个足够小的int值 3 int Start, All; 4 for (int a = 1; a <= Row_num; a++){//起始行 5 for (int c = a; c <= Row_num; c++){ //终结行 6 Start = BC(a, c, Clm_num); 7 All = Start; 8 for (int i = Clm_num; i >= 1; i--){ 9 if(Start < 0) 10 Start = 0; 11 Start += BC(a, c, i); 12 if(Start > All) 13 All = Start; 14 } 15 if(All > maximum) 16 maximum = All; 17 } 18 return maximum; 19 } 20 }
至此,我们完成了新问题的求解和优化,时间复杂度 O(Row_num2 * Clm_num)
先写这么多,我先把扩展问题搞一搞再写别的 T_T