• 29. 最大连续子序列和(一)


    一. 定义

    1.序列:

    给定一组数据,这组数据就叫做序列。这里的数据有可能是一年的交易额,或者有其余的含义。所以数据并不是经过排序的。比如 data = (1, 4, -3, 7, -6, 10).

    2.连续子序列:

    在序列中,任取连续区间的一组数据,叫做连续子序列。

    3.最大连续子序列和:

    把每个子序列看作一个单元,对其中的所有元素求和,获得的值就是一个子序列和。将所有子序列都求和,并从中选出一个最大的,这个值就是最大连续子序列和。

    二.代码实现

    1.实例分析

    假设我们有一组数据,data = (1, 4, -3, 7, -6, 10),第一个子序列是(1) ,它的和就是 1 。第二个子序列是(1, 4),它的和是 5 。其余同理。

    于是我们很快想出一个算法,用于计算最大连续子序列和,代码如下:

     1 int max_sub_sum(const vector<int>& data) {
     2     const int MIN = numeric_limits<int>::min();
     3     int result = MIN;
     4 
     5     for (int range_ctrl = 0; range_ctrl < data.size(); range_ctrl++) {
     6         for (int sub_end = range_ctrl; sub_end < data.size(); ++sub_end) {
     7             int sub_sum = 0;
     8             for (int sub_start = range_ctrl; sub_start <= sub_end; ++sub_start) {
     9                 sub_sum += data[sub_start];
    10             }
    11             if (sub_sum > result) {
    12                 result = sub_sum;
    13             }
    14         }
    15     }
    16 
    17     return result;
    18 }

    2. 代码分析

    显然,最外层循环用于控制大范围,让我们不至于跑到序列的外面。第二层和第三层循环应该看成一个整体,它们用于控制一个子序列的首尾下标。我们仔细观察发现,第二层循环控制子序列的结束下标,第三层循环控制子序列的开始下标。我们先卡住结束位置,再从头开始进行累加,一直加到结束位置(这个结束位置的元素是要计算的,这就是用了 ≤ 符号的原因)。不难看出,算法的时间复杂度是 O(n3),效率并不是很好。经过分析,我们得知,大部分的时间都用在了重复计算上,罪魁祸首就是第三层循环。那么我们来优化一下。

    3. 优化

     1 int max_sub_sum_2(const vector<int>& data) {
     2     const int MIN = numeric_limits<int>::min();
     3     int result = MIN;
     4 
     5     for (int sub_start = 0; sub_start < data.size(); ++sub_start) {
     6         int sub_sum = 0;
     7         for (int sub_end = sub_start; sub_end < data.size(); ++sub_end) {
     8             sub_sum += data[sub_end];
     9             if (sub_sum > result) {
    10                 result = sub_sum;
    11             }
    12         }
    13     }
    14 
    15     return result;
    16 }

    现在只有两层循环。外层循环用于控制子序列的开头,内层循环用于控制子序列的结尾。外层循环的作用其实并没有改变,它仍然防止我们跑到序列的外边去。但是内层循环却不一样了,现在内层循环实际上充当了指定子序列开始的角色,而子序列结尾用序列大小控制就可以。在内层循环中,我们每累加一个元素,产生的和就是一个子序列的和,然后再进行判断即可。这样时间复杂度就成了 O(n2)。

  • 相关阅读:
    Hibernate 4.3.5 JPA实现的常见错误
    Jboss7.1中部署webservice的问题-1
    VS2015 无法启动 IIS Express Web 服务器 解决方案
    Git命令实现本地文件推送到git仓库
    VSCode 首次打开提示“Git installation not found.”解决方案
    VB6 对象库未注册问题
    【使用WCF,发布服务端浏览报错】未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” 中加载类型 “System.ServiceModel.Activation.HttpModule”。
    设计模式一一单例模式
    设计模式一一适配器模式
    .NET Framework 各版本区别(简介)
  • 原文地址:https://www.cnblogs.com/Hello-Nolan/p/13532894.html
Copyright © 2020-2023  润新知