当前位置: 首页 > 编程日记 > 正文

关于最大子段和线性算法的证明

重复题目:

输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

此题最初载于

http://blog.csdn.net/v_JULY_v/article/details/6444021

我在文章中也对其做了总结,并对线性时间的算法做了自己的证明,这里重复如下(其实后面的递归式本身就证明了算法的正确性,这里只是希望通过暴力的方法尝试对从另一个方面对它进行证明,即穷举所有可能出现情况)

关于这道题的证明,我的思路是去证明这样的扫描法包含了所有n^2种情况,即所有未显示列出的子数组都可以在本题的扫描过程中被抛弃。

1 首先,假设算法扫描到某个地方时,始终未出现加和小于等于0的情况。

我们可以把所有子数组(实际上为当前扫描过的元素所组成的子数组)列为三种:

1.1 以开头元素为开头,结尾为任一的子数组

1.2 以结尾元素为结尾,开头为任一的子数组

1.3 开头和结尾都不等于当前开头结尾的所有子数组

1.1由于遍历过程中已经扫描,所以算法已经考虑了。1.2确实没考虑,但我们随便找到1.2中的某一个数组,可知,从开头元素到这个1.2中的数 组的加和大于0(因为如果小于0就说明扫描过程中遇到小于0的情况,不包括在大前提1之内),那么这个和一定小于从开头到这个1.2数组结尾的和。故此种 情况可舍弃

1.3 可以以1.2同样的方法证明,因为我们的结尾已经列举了所有的情况,那么每一种情况和1.2是相同的,故也可以舍弃。

2 如果当前加和出现小于等于0的情况,且是第一次出现,可知前面所有的情况加和都不为0

一个很直观的结论是,如果子段和小于0,我们可以抛弃,但问题是是不是他的所有以此子段结尾为结尾而开头任意的子段也需要抛弃呢?

答案是肯定的。因为以此子段开头为开头而结尾任意的子段加和都大于0(情况2的前提),所以这些子段的和是小于当前子段的,也就是小于0的,对于后面也是需要抛弃的。也就是说,所有以之前的所有元素为开头而以当前结尾之后元素为结尾的数组都可以抛弃了。

而对于后面抛弃后的数组,则可以同样递归地用1 2两个大情况进行分析,于是得证。

这个算法的证明有些复杂,现在感觉应该不会错,至少思路是对的,谁帮着在表达上优化下吧。:-)

后来在《编程珠玑》中看到了对此种算法的解释,实际上,编程珠玑中对于sum小于0后舍弃的定义如下:

maxendinghere = max(maxendinghere, 0)

这里的maxendinghere就是网上常见算法的sum,其意义是以当前元素为结尾的最长字段的长度。

我们可以看到,这其实是一个动态规划解法,最优子结构可以归纳为:

  s[0] = max(a[0], 0)

  s[i] = max(s[i - 1] + a[i], 0)

即如果当前元素加上以前一个元素为结尾的子段和小于0,就把以当前元素为结尾的子段和设为0。实际上这个“子段”是一个空段。我不知道为什么非要区分0和非零,可能是在这道题里“小于0的元素会让整个子段值变小”这个概念很显眼吧,但是这种情况确实忽略如果所有输入为负数的情况,虽然题目假设输入有正有负。

于是我试图改变最优子结构的构造,抛弃0的概念,定义为:

  s[0] = a[0]

  s[i] = max(s[i - 1] + a[i], a[i])

这样看起来比较直观,而且“以元素a[i]为结尾的最大子段和”就不会是一个空子段了。

这种规划方法我不知道是否有什么错误,看起来没什么问题,我实现了一下:

#include <iostream>using namespace std;#define MAX_LEN 100template<class T>
void maxSubArr(T *arr, int len, int &start, int &end, T &max_sum)
{if(len <= 0)return;T max_ending_sum;int i, starts[MAX_LEN]/*the start of the max sub array end with a[i]*/;max_ending_sum = arr[0];max_sum = arr[0];start = 0;end = 0;starts[0] = 0;for(i = 1; i < len; i ++){// max_ending_sum here refers to the maximum subarray length ends with element a[i - 1]if(max_ending_sum + arr[i] > arr[i]){max_ending_sum = max_ending_sum + arr[i];starts[i] = starts[i - 1];}else{max_ending_sum = arr[i];starts[i] = i;}// max_ending_sum now refers to the maximum subarray length ends with element a[i]if(max_ending_sum > max_sum){max_sum = max_ending_sum;start = starts[i];end = i;}}
}int main()
{int a[] = {1, -2, 3, 10, -4, 7, 2, -5};int len = 8;//int a[] = {-1, -2, -3, -10, -4, -7, -2, -5};//int len = 8;int start, end, max_sum, i;maxSubArr(a, len, start, end, max_sum);cout << "maximum summary : " << max_sum << endl;cout << "the subarray : ";for(i = start; i <= end; i ++){cout << a[i] << " ";}
}


输出为:

maximum summary : 18
the subarray : 3 10 -4 7 2

特别的,当输入变为:

int a[] = {-1, -2, -3, -10, -4, -7, -2, -5};

全部为负时,这个算法不用特殊考虑就可以得出正确结果:

maximum summary : -1
the subarray : -1

看起来没什么错~

相关文章:

SQL Server使用侦听器IP访问时遇到The target principal name is incorrect. Cannot generate SSPI context...

SQL Server使用侦听器IP访问时遇到"The target principal name is incorrect. Cannot generate SSPI context" 原文:SQL Server使用侦听器IP访问时遇到"The target principal name is incorrect. Cannot generate SSPI context"在测试SQL Server 2016 Alwa…

linux+Qt 下利用D-Bus进行进程间高效通信的三种方式

linuxQt 下利用D-Bus进行进程间高效通信的三种方式 原文链接: https://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html D-Bus概述 什么是D-Bus&#xff1f; D-Bus是一种进程间通信的机制&#xff0c;它被设计成为一种低开销、低延迟的IPC&#xff0c;并被多种桌面环…

xbmc-12.0稳定版代码初探 (2) —— XBMC_HOME

XBMC工程在debug时要设置XBMC_HOME的环境 用于指定ffmpeg的Dll文件位置&#xff0c;语言等等 xbmc/filesystem/SpecialProtocol.cpp 定义了一些如&#xff1a; CSpecialProtocol::SetXBMCPath();的函数 xbmc\Application.cpp InitDirectoriesWin32(); -> CUtil::GetHomePat…

python是最好的语言 永远二十岁_Python是世界上最好的语言吗?

编程语言的选择是IT圈子永远的争议。在任意一个程序员聚集的场合&#xff0c;喊一句类似于“PHP是世界上最好的语言”这样的话&#xff0c;肯定会惹来不少人和你争论得面红耳赤。那么&#xff0c;python是世界上最好的语言吗&#xff1f;这个我不敢说&#xff0c;但是至少他应该…

(转)Android笔记--handler机制

一、重要参考资料 【参考资料】目前来看&#xff0c;下面的几个网址中的内容质量比较不错&#xff0c;基本不需要再读别的网址了。1、android消息机制一http://xtfncel.javaeye.com/blog/6635172、Android消息机制二http://xtfncel.javaeye.com/blog/6635183、Android线程间通信…

自制操作系统Antz(9)——实现内核 (下) 实现图形化界面

Antz系统更新地址&#xff1a; https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址&#xff1a;https://www.cnblogs.com/LexMoon/category/1267413.html Github项目地址&#xff1a;https://github.com/CasterWx/AntzOS 在前几天的任务中&#xff…

python迷宫万花筒代码_利用广度优先遍历搜索迷宫的python源代码

广度优先遍历简称为DFS&#xff0c;是数据结构中比较常用的一个算法&#xff0c;主要原理是采用队列先进先出的规则&#xff0c;一层一层的访问图的节点。而迷宫问题接近与遍历&#xff0c;但是不同于遍历&#xff0c;主要考虑是采用栈的形式标记路径&#xff0c;并对当前节点和…

联想拯救者Y9000-ubuntu-nvidia-驱动安装

概述 由于联想拯救者Y9000的硬件都比较新&#xff0c;所以在安装ubuntu 的时候会有很多驱动的问题&#xff0c;本文主要讲解安装nvidia驱动的问题&#xff0c;如网卡、触摸板无效的其他问题请在我的其他文章中查找 友情提示 安装完系统之后先插网线装ssh服务&#xff0c; 确…

修改远程桌面端口

修改远程桌面端口需要两个步骤&#xff1a;  1、打开注册表 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp]&#xff0c;修改右边PortNamber的值&#xff0c;其默认值是3389&#xff0c;修改成所希望的端口即可&#xff0c;例如3…

开发管理 CheckLists(4) -风险管理

本文章主要介绍在项目启动前怎么样分步骤的去识别风险,才去什么方式去识别风险. 有需要做风险识别的朋友可以按照下面的步骤简单的走上一遍,或者可以提高项目的成功率 注意&#xff1a;本文章只是你做风险识别的chekcLists ,上面提到的一些分析方法都只是简单的介绍…

python的深拷贝与浅拷贝

对于list, set, dict来说, 直接赋值. 其实是把内存地址交给变量. 并不是复制⼀份内容. 两个变量的内容其实为一个地址,如果要在复制的同时分配新的地址则需要用到深拷贝和浅拷贝的命令 lst1 ["何炅", "杜海涛","周渝⺠", ["麻花藤", …

safari post 请求接收不到_我是谁?我在哪?我要到哪去?——HTTP请求头

各位小白帽们好又到了新一期的知识点咯在正片开始之前再次提醒一下各位因为联盟管理的需要本周五(12月4日)5点半将会对各位在平台的答题分数进行统计筛选部分排名靠前的童鞋作为核心的正式会员考核压力来了大家是不是有点紧张呢只要积极学习知识积极参与答题向本AI卖萌要flag相…

SharePoint 2013 配置开发环境,需安装VS2012插件

SharePoint 2013已经安装好了&#xff0c;接下来就是配置开发环境&#xff0c;安装VS2012&#xff0c;但是&#xff0c;装好了以后&#xff0c;发现没有SharePoint 2013开发的支持&#xff0c;如下图&#xff1a; 然后&#xff0c;去网上查找资料&#xff0c;VS2012对SharePoin…

联想拯救者Y9000-ubuntu-U盘启动失败解决方法

注意事项 1、U盘要是USB3.0的U盘&#xff0c;否则基本会失败 安装到最后的时候报一个 cd/dvd 设备 low speed的故障 2、bios 设置 硬盘模式 选择 AHCImode 模式&#xff0c; 否则刷机不成功 3、 U盘镜像的烧录方式&#xff0c; 实测windows 下的rufus工具有效

RedHat Enterprise 5.1下OpenLDAP的配置及PAMNSS的配置

服务器端 192.1.0.160 客户机端 192.1.0.221 一、在服务器端配置LDAP服务&#xff1a; 1.下载 openldap-2.4.11.tar.gz和db-4.7.25.tar.gz 2.安装BerkeleyDB #rpm -qa|grep db # tar xvf db-4.7.25.tar.gz # cd db_4.7.25# cd build_unix/# ../dist/configure -prefix/usr/loca…

pwn with glibc heap(堆利用手册)

前言 ​ 对一些有趣的堆相关的漏洞的利用做一个记录&#xff0c;如有差错&#xff0c;请见谅。 ​ 文中未做说明 均是指 glibc 2.23 ​ 相关引用已在文中进行了标注&#xff0c;如有遗漏&#xff0c;请提醒。 简单源码分析 ​ 本节只是简单跟读了一下 malloc 和 free 的源码&am…

COCO KeyPoints关键点数据集准备

COCO KeyPoints关键点数据集准备 概述 网上搜了一圈&#xff0c;coco关键点数据集准备的内容比较少&#xff0c;这里写一篇完成的标注流程到数据集准备的文章&#xff0c;以备后忘 标注工具 coco官方标注工具: coco–annotator https://github.com/jsbroks/coco-annotator …

Boost 1.53.0 发布,可移植的C++标准库

Boost 1.53.0 发布了&#xff0c;包含了 5 个新的库&#xff0c;修复了一些安全漏洞以及 Boost.Locale 组件的 bug 。 新增的 5 个库包括&#xff1a; Boost.AtomicBoost.CoroutineBoost.MultiprecisionBoost.Numeric.OdeintBoost.Lockfree完整改进记录说明请看 changelog 下载…

华为云客户端_从技术角度解读华为云手机之于普通用户的可行性

9月1日&#xff0c;华为云宣布&#xff0c;华为首创全球首个ARM芯片的“云手机”正式公测。此消息一出&#xff0c;普通消费市场一片赞美之声&#xff0c;想必大家更多的想法是终于让华为找到了一个应对当前手机困局的解决方案了。据悉&#xff0c;华为云鲲鹏手机早在今年3月就…

c#获取应用程序目录

string str1 Process.GetCurrentProcess().MainModule.FileName;//可获得当前执行的exe的文件名。 string str2Environment.CurrentDirectory;//获取和设置当前目录&#xff08;即该进程从中启动的目录&#xff09;的完全限定路径。//备注 按照定义&#xff0c;如果该进程在本…

【BZOJ5311/CF321E】贞鱼/Ciel and Gondolas(动态规划,凸优化,决策单调性)

【BZOJ5311/CF321E】贞鱼/Ciel and Gondolas&#xff08;动态规划&#xff0c;凸优化&#xff0c;决策单调性&#xff09; 题面 BZOJCF洛谷 辣鸡BZOJ卡常数&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 辣鸡BZOJ卡常数&#xff01;&#xff01;&…

python定时任务contrib_django+celery配置(定时任务+循环任务)

下面介绍一下djangocelery的配置做定时任务1.首先介绍一下环境和版本python2.7django 1.8.1celery 3.1.23django-celery 3.1.172.celery的安装sudo pip install celery3.1.23sudo pip install django-celery3.1.173.新建一个项目(1)django-admin startproject django_celery…

CenterNet KeyPoints 关键点训练自己的数据

概述 网上搜了一圈&#xff0c;关于CenterNet 训练关键点数据的资料非常少&#xff0c;而且讲得都很模糊&#xff0c;没法解决实际问题&#xff0c;也未说明细节和要素。在踏坑许久之后&#xff0c;才跑通CenterNet的关键点训练&#xff0c;于是记录一下踏坑历程&#xff0c;以…

Java学习笔记---字符类型

一、字符类型也算是整数类型的一种 字符类型在内存中占有2个字节&#xff0c;可以用来保存英文字母等字符。计算机处理字符类型时&#xff0c;是把这些字符当成不同的整数来看待&#xff0c;因此&#xff0c;严格说来&#xff0c;字符类型也算是整数类型的一种&#xff08;小写…

我的家庭私有云计划-16

嗯&#xff0c;上午测试S2S的稳定性&#xff0c;改掉几个bug。还挺忙的。这会儿让机器跑测试去&#xff0c;腾出点时间&#xff0c;我们接着聊。 呵呵&#xff0c;昨天哪&#xff0c;已经有朋友批评我了&#xff0c;说我有点贪大求全&#xff0c;这个论坛什么的没必要自己实现&…

“cyl projection cannot cross pole” 解决方法

解决方法&#xff1a; 1、尝试更新NumPy以及相关模块&#xff1a; 在CMD里面执行 conda update –all 遇到提示选择yes/y 更新完毕后看是否可以载入。 发现并不能成功更新&#xff0c;于是采取了下面方法&#xff1a; 2、如果方法一不能解决&#xff0c;那么尝试卸载相关库&…

使用ubuntu(18.04) 作为软路由器连接互联网

使用ubuntu&#xff08;18.04&#xff09; 作为软路由器连接互联网 背景: 最近要用ubuntu机器作为中继路由&#xff0c;需要配置一下&#xff0c;但是内网外网网上找了一圈&#xff0c;五花八门的&#xff0c;照着做没有一个靠谱的&#xff0c;遇到的问题也没有任何说明&#…

程序员肿么了?为何总被认为是“屌丝”

没有想到会这么多人&#xff0c;有一点我强调一下&#xff0c;我的标题是被认为&#xff0c;而不是说真是。其实程序员相比其他行业不见得差&#xff0c;只是社会整体认可度不高。&#xff08;或者说认知&#xff09; 本文纯属闲时娱乐&#xff0c;请勿当真&#xff0c;请勿较真…

python空值填充_pandas | DataFrame基础运算以及空值填充

今天是pandas数据处理专题的第四篇文章&#xff0c;我们一起来聊聊DataFrame的基本运算。上一篇文章当中我们介绍了DataFrame数据结构当中一些常用的索引的使用方法&#xff0c;比如iloc、loc以及逻辑索引等等。今天的文章我们来看看DataFrame的一些基本运算。数据对齐我们可以…

Python学习之路基础篇--10Python基础,函数进阶

1 命名空间 对于Python 来说命名空间一共有三种 1 内置命名空间 —— Python 解释器 就是Python 解释器一启动就可以使用的名字&#xff0c;储存在内置命名空间中。内置的名字在启动解释器的时候被加载进内存里 2 全局命名空间 —— 我们所命名的&#xff0c;但不是函数中的代码…