求最大子序列和的四种方法

2023-11-14

求一个给定序列的连续子序列中和最大的那个子序列的和,下边方法只求和,没有找出最大子序列。

用到的头文件和宏定义如下

#include "stdafx.h"
#include<vector>
#include <string>
#include <fstream>
#include <random>
#include <time.h>
#include <iostream>
typedef long int l_int;

三层for循环穷举法

该方法设计三层for训话,第一层设定求和序列的开始位置,第二层设定求和位置的结束位置,第三层对子序列进行求和。例如该序列为a1 a2 a3 a4 a5 a6,那么先a1为开始位置,分别以a2、a3、a4、a5、a6为结束位置,对五个子序列分别求和,找出其最大和sum。接着以a2为起始位置,a3、a4、a5、a6为结束位置,分别求出四个子序列的和,并且和sum比较,找出最大和。以此类推。
l_int MaxSubSum2(std::vector<int> data){
    time_t t1,t2;
    time(&t1);
    l_int sum = 0;
    for (int i=0;i<data.size();i++)
    {
        for (int j=i;j<data.size();j++)
        {
            l_int temp = 0;
            for (int k=i;k<j;k++)
            {
                temp += data[k];
            }
            if (temp > sum)
            {
                sum = temp;
            }
        }
    }
    time(&t2);
    std::cout<<"MaxSubSum2: "<<sum<<" time:"<<t2-t1<<std::endl;
    return sum;
}

两层for穷举法

观察三层for穷举法,会发现在计算起始点相同的各个子序列和时,长序列包括了各个短序列的和。例如计算a1+a2+a3时,需要计算a1+a2。计算a1+a2+a3+a4+a5+a6时,可以分别得出各个子序列a1+a2、a1+a2+a3、a1+a2+a3+a4、a1+a2+a3+a4+a5的和,那么三层for穷举法可以做一下修改:
l_int MaxSubSum3(std::vector<int> data){
    time_t t1,t2;
    time(&t1);
    l_int sum = 0;
    for (int i=0;i<data.size();i++)
    {
        l_int temp = 0;
        for (int j=i;j<data.size();j++)
        {
            temp += data[j];
            if (temp > sum)
            {
                sum = temp;
            }
        }
    }
    time(&t2);
    std::cout<<"MaxSubSum3: "<<sum<<" time:"<<t2-t1<<std::endl;
    return sum;
}

一层for循环穷举法

如果a[i]是负数那么它不可能代表最有序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过用a[i+1]作为起点来改进。类似的有,任何的负的子序列不可能是最优子序列的前缀。例如说,循环中我们检测到从a[i]到a[j]的子序列是负数,那么我们就可以推进i。关键的结论是我们不仅可以把i推进到i+1,而且我们实际可以把它一直推进到j+1。

l_int MaxSubSum4(std::vector<int> data){
    time_t t1,t2;
    time(&t1);
    l_int sum = 0;
    l_int temp = 0;
    for (int i=0;i<data.size();i++)
    {
            temp += data[i];
            if (temp > sum)
            {
                sum = temp;
            }
            else if(temp<0){
                temp = 0;
            }
    }
    time(&t2);
    std::cout<<"MaxSubSum4: "<<sum<<" time:"<<t2-t1<<std::endl;
    return sum;
}

递归法

最大子序列可能在三个地方出现,或者在左半部,或者在右半部,或者跨越输入数据的中部而占据左右两部分。前两种情况递归求解,第三种情况的最大和可以通过求出前半部分最大和(包含前半部分最后一个元素)以及后半部分最大和(包含后半部分的第一个元素)相加而得到。(算法导论)
l_int max3(l_int left,l_int right, l_int cross );
l_int re_MaxSubSum1(std::vector<int> data , int left, int right);

l_int MaxSubSum1(std::vector<int> data){
    time_t t1,t2;
    time(&t1);  
    l_int sum = re_MaxSubSum1(data,0,data.size()-1);
    time(&t2);
    std::cout<<"MaxSubSum1: "<<sum<<" time:"<<t2-t1<<std::endl;
    return sum;
}

l_int re_MaxSubSum1(std::vector<int> data , int left, int right){
    if (left == right)
    {

        //return (data[left]>0?data[left]:0);
        return data[left];
    }
    int cent = (left+right)/2;
    l_int MaxLeft = re_MaxSubSum1(data, left,cent);
    l_int MaxRight = re_MaxSubSum1(data,cent+1,right);


    l_int CrossSum_Ltemp = 0;
    l_int CrossSumL = 0;
    for (int i = cent;i>=left;i--)
    {
        CrossSum_Ltemp += data[i];
        if (CrossSum_Ltemp>CrossSumL)
        {
            CrossSumL = CrossSum_Ltemp;
        }
    }

    l_int CrossSum_Rtemp = 0;
    l_int CrossSumR = 0;
    for (int i = cent+1;i<=right;i++)
    {
        CrossSum_Rtemp += data[i];
        if (CrossSum_Rtemp>CrossSumR)
        {
            CrossSumR = CrossSum_Rtemp;
        }
    }
    l_int SumCross = CrossSumL+CrossSumR;
    return max3(MaxLeft,MaxRight,SumCross);
}

l_int max3(l_int left,l_int right, l_int cross ){
    l_int temp = left;
    if (temp < right)
    {
        temp = right;
    }
    if (temp < cross)
    {
        temp = cross;
    }
    return temp;
}

http://blog.163.com/kevinlee_2010/blog/static/169820820201010495438247/作者对四种方法也做了总结,本文主要参考该作者的方法。

测试

读测试文件函数

将测试文件的数据读入容器

bool readfile(std::vector<int> &data,std::string filename){
    std::ifstream infile(filename);
    if (!infile)
    {
        return false;
    }
    int s;
    while (infile>>s)
    {
        data.push_back(s);
    }
    return true;
}
生成测试文件函数

用C++11标准的随机数引擎和分布生成给定数量,一定范围内的随机数

bool writefile(l_int num,int max_nun,std::string filename = "text.txt"){
    std::ofstream outfile(filename);
    if (!outfile)
    {
        return false;
    }
    std::uniform_int_distribution<int> u(0,max_nun);
    std::default_random_engine e;
    for (int i =0;i<num;i++)
    {

        outfile<<(u(e)%2==0?u(e):~u(e))<<'\n';
    }
    return true;
}
测试函数
分别调用四种方法,观察运行时间,实验证明,一层for循环穷举法换时间最少,三层for循环最多,但数据数目上千后递归法耗时不比二层for循环穷举法短,主要因为其间函数调用耗时长。
int _tmain(int argc, _TCHAR* argv[])
{
    if(!writefile(100000,200)){
        return 0;
    }
    std::vector<int> data;
    if(!readfile(data,"text.txt")){
        return 0;
    }   
    l_int sum4 = MaxSubSum4(data);
    l_int sum3 = MaxSubSum3(data);
    l_int sum1 = MaxSubSum1(data);
    l_int sum2 = MaxSubSum2(data);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

求最大子序列和的四种方法 的相关文章

随机推荐

  • HttpSession对象的创建过程

    1 概念 Session代表服务器与浏览器的一次会话过程 这个过程是连续的 也可以时断时续的 在Servlet中 session指的是HttpSession类的对象 这个概念到此结束了 也许会很模糊 但只有看完本文 才能真正有个深刻理解 2
  • idea打war的问题

    大家好 我是雄雄 欢迎关注微信公众号 雄雄的小课堂 前言 今天 记录个到现在为止还没搞清的问题 这个问题浪费了我几个小时的时间 基本上昨天晚上啥也没干 都在弄这个了 主要是还没弄出来 在各个技术群里面也都问了 有的说是项目的jar问题 有的
  • LCD1602液晶显示屏

    介绍 LCD1602液晶显示屏是一种字符型液晶显示模块 可以显示ASCll码的标准字符和其他一些内置的特殊字符 还可以内置8个自定义字符 显示容量 16 2个字符 每个字符为5 7点阵或5 10点阵 一 引脚介绍 VO 对比度调节电压 RS
  • 定位及居中

  • 深度学习入门——神经网络

    神经网络 神经网络是一种受到人脑神经系统启发的机器学习模型 它由一系列相互连接的人工神经元组成 这些神经元以层次结构排列 每个神经元接收来自上一层神经元的输入 并根据权重和激活函数对输入进行加权处理 然后将输出传递给下一层神经元 如下图是一
  • 【随笔】在vue项目使用icon

    Vue引用icon图标 利用i标签 快速添加页面图标 利用i标签 快速添加页面图标 之前写项目遇见图标都是下载成icon然后用img展示 但是图标写多了就会变得特变麻烦 光下载的图标就会占很大空间 所以学着用i写 首先进入项目 在项目下建一
  • python model函数_python--model进阶

    一 QuerySet 1 可切片 使用Python 的切片语法来限制查询集记录的数目 它等同于SQL 的LIMIT 和OFFSET 子句 gt gt gt Entry objects all 5 LIMIT 5 gt gt gt Entry
  • 【动态规划】LCS算法:求两字符串最大公共子序列/删除字符使成为回文串

    问题描述 给定一个字符串s 你可以从中删除一些字符 使得剩下的串是一个回文串 如何删除才能使得回文串最长呢 输出需要删除的字符个数 例如 输入 google 输出 2 思路 回文串通常可以用逆序的方式寻找思路 例如字符串google逆序后e
  • 运维小知识之CDN内容分发网络原理解析

    0x00 前言简述 基础概念 工作原理 组成部分 应用场景 0x01 基础配置 CDN 入门配置 CDN 跨域设置 CDN 响应头参数 扩充 0x02 边缘脚本与程序 EdgeScript 边缘脚本 EdgeRoutine 边缘程序 0x0
  • 【linux】宝塔面板安装命令

    一 查看是否安装 宝塔面板 bt 14 已安装会列出宝塔登录地址 否则 bash bt command not found 下载及安装命令 yum install y wget wget O install sh http download
  • 移动DICT项目是什么?

    DICT项目 我们运营商的伙伴 很多人都知道我们的DICT 但是大家知不知道什么是DICT 你想一想 所谓的DICT 就是指的大数据技术与IT和CT的深度融合 实际上 DICT的可以拆分成三个词 第一个DT 云和大数据的技术 第二个IT 信
  • LeetCode--初级算法--反转链表

    参考 反转链表的方法 反转一个单链表 示例 输入 1 gt 2 gt 3 gt 4 gt 5 gt NULL 输出 5 gt 4 gt 3 gt 2 gt 1 gt NULL 进阶 你可以迭代或递归地反转链表 你能否用两种方法解决这道题 分
  • pandas学习笔记--取表格中特定行或列或特定位置元素

    先生成一个演示dataframe df pd DataFrame np random randn 5 5 columns A B C D E index a b c d e df 取前两行 df 0 2 取后两行 df 2 取倒数第二行 d
  • 什么是DAO,DAO是什么?DAO全面解析

    什么是DAO DAO是什么 DAO是Decentralized Autonomous Organizationd简写 即去中心化自治组织 有时也被称为分布式自治公司 DAC 有共同的目标或是共识 有明确的核心价值观 它的民主化的投票机制 决
  • idea Maven异常:Could not find artifact(本地仓库确实存在)

    首先检查自己的maven环境有无问题 1 首先尝试清楚idea中的缓存如下图所示 当pom没有爆红时 按照上图操作还是无效 可以尝试重新新建一下自己的repository把自己原来的仓库重命名备份下以防万一 我的是这样操作解决了问题 希望能
  • 实战攻防演习之红队

    0x00 什么是红队 红队 一般是指网络实战攻防演习中的攻击一方 红队一般会针对目标系统 人员 软件 硬件和设备同时执行的多角度 混合 对抗性的模拟攻击 通过实现系统提权 控制业务 获取数据等目标 来发现系统 技术 人员和基础架构中存在的网
  • 【JavaEE】多线程案例-单例模式

    文章目录 1 前言 2 什么是单例模式 3 如何实现单例模式 3 1 饿汉模式 3 2 懒汉模式 4 解决单例模式中遇到的线程安全问题 4 1 加锁 4 2 加上一个判断解决频繁加锁问题 4 2 解决因指令重排序造成的线程不安全问题 1 前
  • 应用场域的深度融合与创新构想

    近年来 随着人工智能技术的迅速发展 自然语言处理技术也取得了显著的进步 其中 ChatGPT作为一种高效的自然语言处理模型 已经在许多领域得到了广泛的应用 本文主要围绕ChatGPT的调研分析以及其与应用场域的结合构想展开讨论 一 Chat
  • BigDecimal转String字符串的代码

    BigDecimal转String字符串的代码 Posted on 2016 06 28 11 17 上善其若水 厚德载物 阅读 8896 评论 0 编辑 收藏 举报 bigdeciaml stripTrailingZeros toPlai
  • 求最大子序列和的四种方法

    求一个给定序列的连续子序列中和最大的那个子序列的和 下边方法只求和 没有找出最大子序列 用到的头文件和宏定义如下 include stdafx h include