zoukankan      html  css  js  c++  java
  • 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)。

  • 相关阅读:
    Nginx 学习笔记(七)如何解决nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
    jQuery基础 (四)——使用jquery-cookie 实现点赞功能
    Travis CI实现持续部署
    三大云安全工具(CASB、CSPM、CWPP)的使用场景
    数据访问安全代理 CASB
    SDP(软件定义边界)让SDN更安全,你的对面可不能是一条狗!
    从BeyondCorp说起
    [Docker] Docker整体架构图
    当博弈论遇上机器学习:一文读懂相关理论
    用Rust重写Linux内核模块体验
  • 原文地址:https://www.cnblogs.com/Hello-Nolan/p/13532894.html
Copyright © 2011-2022 走看看