最大子数组问题

最大子数组问题仅对存在负数的数组才有意义。

这里根据《算法导论(第三版)》第四章的4.1节的练习题 4.1-5进行拓展研究。用JavaScript实现最大子数组的查找。

准备工作

先定义两个用于生成随机数组的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 生成一个m、n之间的整数 */
function random(m,n){
var i=Math.random();
return Math.round((n-m)*i+m);
}
/* min: 数组下界
* max: 数组上界
* len:生成的数组的长度
*/
function getRandomArr(min,max,len){
var resultArr=[];
for(var i=0;i<len;i++){
resultArr.push(random(min,max));
}
return resultArr;
}
var A = getRandomArr(-20, 20, 6);
console.log(A);

线性复杂度的算法:Kadane算法

这个问题用动态规划的方法来解决会更有效,而不是分治策略。例如下面的Kadane算法。

算法的关键在于:遍历、累加的过程中,曾经出现的最大子数组是会被记录下来的。重置下标时,只是为了寻找“潜在”的下一个最大子数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Kadane算法
* 又被称为扫描法
* 该算法用到了一个启发式规则:如果前面一段连续子数组的和小于0,那么就丢弃它。
*/
function Kadane(A){
var max = A[0],
sum = 0,
sum_low = 0, sum_high = 0, /* 这两个值保存了当前累计计算的、和非负的子数组的下标起始值 */
max_low = 0, max_high = 0;
for(var i = 0; i<A.length; i++){
if(sum >= 0){
sum += A[i];
sum_high = i;
} else{
sum = A[i];
sum_low = i;
sum_high = i;
}
if(sum > max){
max_low = sum_low;
max_high = sum_high;
max = sum;
}
}
return {
maxSum: max,
low: max_low,
high: max_high
};
}
console.log(Kadane(A));
Share