微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

第二种算法如何变得比第一种更有效,子阵列的右侧如何在第二种算法中移动?

如何解决第二种算法如何变得比第一种更有效,子阵列的右侧如何在第二种算法中移动?

问题 - 给定一个包含 n 个数字的数组,我们的任务是计算最大子数组和,即数组中连续值序列的最大可能和 大批。当数组中可能有负值时,这个问题很有趣。数组 = {-1,2,4,-3,5,-5,2}。

一个算法-

int best = 0;
    for (int a = 0; a < n; a++) {
        for (int b = a; b < n; b++) {
            int sum = 0;
            for (int k = a; k <= b; k++) {
                sum += array[k];
            }
        best = max(best,sum);
        }
    }
cout << best << "\n"; 

第二种算法-

int best = 0;
    for (int a = 0; a < n; a++) {
        int sum = 0;
        for (int b = a; b < n; b++) {
            sum += array[b];
            best = max(best,sum);
        }
    }
cout << best << "\n";

这就是书中所说的 - 通过从中删除一个循环可以很容易地使算法 1 更高效。这可以通过在右端计算总和的同时实现 子阵移动。

第二个算法中子数组的右端如何移动,谁能给我解释一下?

解决方法

第一个版本对从索引 a 开始到索引 b 的子数组的所有子数组总和进行蛮力比较,我们称这些子数组总和为 subsum(a,b)

第二个版本也相当暴力,但使用了 subsum(a,b+1) == subsum(a,b) + array[b+1] 的事实。

换句话说:要知道第一个 say 10 元素的总和,您可以使用先前计算的第一个 9 元素的总和。如果你用笔和纸解决这个问题,这将是显而易见的,但第一个版本并没有这样做。相反,第一个版本对 ab 的所有组合有两个嵌套循环,并且总是以新的 sum = 0 开头,这相当浪费。


只考虑第一个版本的外循环:

for (int a = 0; a < n; a++) {
    for (int b = a; b < n; b++) {
        int sum = 0;
        // ...
    }
}

此处 //... 计算 subsum(a,b)

在第二个版本中:

int best = 0;
for (int a = 0; a < n; a++) {
    int sum = 0;
    for (int b = a; b < n; b++) {
        sum += array[b];
        best = max(best,sum);
    }
}

外循环负责在不同的“左端”启动子数组。而内循环“移动”了“右端”。

内循环体计算subsum(a,b),内循环的下一次迭代“移动”b到下一个索引以计算subsum(a,b),使用上述关系:{{1} }.因为subsum(a,b) == subsum(a,b-1) + array[b]在内循环中是固定的,所以作者说的是“移动右端”。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。