最大字段和的改进-最接近0或某一其他固定值的字段和(习题10)
一、对于最接近0的字段和求解
1、最接近0就相当于字段和的绝对值最小,此时问题等价于求绝对值最下的字段和。针对此,可以设置一个绝对值结构体,结构如下:
struct absVal { float value; //绝对值 bool flag; //标志位,true表示为非负数,否则为负数 };
这样,可以将最简单的扫描算法改写成如下:
简单法求最接近0的字段和
float maxSum_easy(int n, int* a, int& besti, int& bestj) //最简单的方法,复杂度为O(n^3) { int i = 0, j = 0, k = 0, sum = 0,sum_t = 0; absVal maxSoFar; if (a[0]>0) { maxSoFar.value = a[0]; maxSoFar.flag = true; } else { maxSoFar.value = -a[0]; maxSoFar.flag = false; } for (i = 0; i < n; ++i) for ( j = i; j < n; ++j) { sum = 0; for (k = i; k<=j; ++k) sum += *(a+k); sum_t = abs(sum); if (sum_t < maxSoFar.value) { maxSoFar.value = sum_t; if (sum_t != sum) maxSoFar.flag = false; else maxSoFar.flag = true; besti = i; bestj = j; } } if (maxSoFar.flag) return maxSoFar.value; else return -maxSoFar.value; }
同样可以改写另外两种O(n2)的算法,这里改进动态规划的算法如下:
动态规划方法求解最接近0字段和
struct absVal maxSum_sm(int* a, int n) //扫描算法,时间复杂度为O(n) { absVal maxSoFar, maxendinghere, temp, absa; int i =0; //赋初值 if (a[0] >= 0) { maxSoFar.value = a[0]; maxSoFar.flag = true; maxendinghere.value = a[0]; maxendinghere.flag = true; } else { maxSoFar.value = -a[0]; maxSoFar.flag = false; maxendinghere.value = -a[0]; maxendinghere.flag = false; } //从1->n-1依次扫描 for (i = 1; i < n; ++i) { //求每一个元素的绝对值 if (a[i] >= 0) { absa.value = a[i]; absa.flag = true; } else { absa.value = -a[i]; absa.flag = false; } //求结束位置为i的最接近0的字段和 if (maxendinghere.flag && absa.flag || !maxendinghere.flag && !absa.flag) { temp.value = maxendinghere.value + absa.value; temp.flag = absa.flag; } else if(maxendinghere.value >= absa.value) { temp.value = maxendinghere.value - absa.value; temp.flag = maxendinghere.flag; } else { temp.value = absa.value - maxendinghere.value; temp.flag = absa.flag; } if (temp.value < absa.value) { maxendinghere.value = temp.value; maxendinghere.flag = temp.flag; } else { maxendinghere.value = absa.value; maxendinghere.flag = absa.flag; } if (maxendinghere.value < maxSoFar.value) maxSoFar = maxendinghere; } return maxSoFar; }
2、课本上所给的答案并不是如此做的,而是设置一个累加数组cum,使得cum[i]=x[0]+...+x[i]。则sum(x[l..u])=cum[u]-cum[l-1],通过定位cum中最接近的两个元素来找出和最接近0的子向量和,而这可以通过排序数组,在O(nlogn)时间内完成。任何能够解决该问题的算法都能用于解决元素“唯一性”问题。
二、对于最接近某一个值v的字段和求解方法
类似于最接近0的方法求解,即求与v绝对值差的绝对值最小的字段和,可以同样实现之。