题目描述

  对于一个给定的数列,求该数列最大的子串和(连续)

问题分析

  处理发生区间上的问题时,经常会用一个非常简单经典的思路——部分和(也有叫前缀和)。部分和的思想在很多复杂的区间上的算法中都有应用,它解决的问题是,在一个序列a[1..n]中快速求得任意子串a[n] + a[n + 1] + ... a[n + m]的和,具体过程非常简单,在原序列里,a[i]保存了在序列中第i个位置的数值,根据原序列生成一个新数列s[1..n],其中s[j] = sum{a[i], 0 <= i <= j},那么对于任意子串和就有a[p..q]=s[q]-s[p-1]。这样以来我们就可以在相同的空间复杂度下快速访问更多信息,这样完全不用保留原数组,因为对于任意原数组中的数值都有a[i] = s[i]-s[i-1]。有了新工具我们再来考虑原问题,先从最简单的思路,问题要求找出最大子串和,那么就枚举每一个子串的起始位置,找一个最大的子串,公式表示就是ans=max{s[j]-s[i],0<=i<=j,0<j<=n},从这个式子可以发现,任意子串和都有sum=s[j]-s[i],(0<=i<=j)的形式,其中s[j]的数值固定不同,那么我们只需要找到min{s[i],0<=i<j}就能找到以j结尾最大的子串,这个工作只要的经过简单的预处理就可以得到,那么我们最后实际需要做的工作就是枚举一遍子串的结尾点,结算该结尾最大的子串,并统计其中最大值即可,时空复杂度均为O(n)。

  除了以上解法,我还在其他同学的博客发现了一些其他更好的解法,事实上我们发现一个序列里的数有正有负,其中最大子串是其中一些连续的数,这些数也是有正有负的,但其中真正“做出贡献”的只有正数,我们选取了一段负数是因为在这段负数的前后必定有贡献比其损失更多的正数,所以可以简单地得到一个结论,最大子串首尾必须是正数,(如果有一段时负数的话那么去掉这一段得到的子串比原来更大,与假设矛盾)。根据这个结论我们可以得到一个新的算法,把原数列分成正数段和负数段

  1. 原序列:
    a=[1 - - - - 5]
  1. 划分后:
    () (- -) ( ) (- -) ( )
  2. b=[1 - - 12]

在新数列上我们枚举每一正数作为起点,然后不断加上他的后继,若当前结果优于已得到的答案则更新答案,当加入一个后继发现当前结果小于等于0时,就结束这次操作找下一个正数迭代。先在简单证明一下它的合理性,前面已经说明了最大子串肯定开始与正数,那么仅需证在每次枚举起始点的操作中都考虑到了所有情况,假设当前起始点为i,结尾枚举到了j时发现b[i..j]<=0,那么对于任意以j+1起始的子串来说,b[i..j] + b[j..k] < b[j..k],因此吧b[i..k]不会比b[j..k]更优,无需进行后面的枚举,证毕。但是现在看来这个算法最坏的时间复杂度是O(n^2),比前者逊色不少,但是这个算法还能再优化,如果以第i个位置为起点的查找到j点结束了,且存在一个b[k]>0,i<k<j,那么对于任意b[k..m],b[i..m]都会比b[k..m]优,因为在枚举过程中保证了b[i..k]>0,同时也保证了b[k..j]<0,那么当我们枚举到j结束之后以j+1处的元素为起始点继续枚举即可,如果全是非正数的话输出最大元素即可,这样这个算法就达到了O(n)的时间复杂度,达到了和前面算法一样的效率。

一些讨论

  第二个算法想写上转载地址,但是实在懒得找了,原作者介意的话请速与我联系。在原博中作者自语此法为奇技淫巧(大概同意,忘了原话了),与标准答案略有差距,我个人还是非常喜欢这种接法的, 通过发现问题的新的性质来解决问题本身就会加深对问题的理解,同时带来新的启发,而且这种方法同表程相比代码长度,时空复杂度,思维难度大体相当,没有孰优孰劣之分。有了这些方法原题目现在看上去就so easy了,我们可以简单思考一下扩展问题。

求最小子串和;只需简单给每个数转换正负。

序列尾部会增加或删除元素;在第一种方案中给每个点记录一下当前状态,增删后从断点继续计算即可。

序列长度固定,其中一些元素的值会改变;可以使用标程中O(nlogn)的算法,将每次计算的节点信息保留,元素改变后同时改变影响的节点,时间复杂度为O((m+n)logn),其中m为改变的次数。

序列内部的元素会删除增加,没有想到什么更好的办法。

最大子串积,。。。。。

模m下的最大子串积,。。。。。

其他

  我选择的参考书是第二版的《代码大全》

homework-01 最大子串和的更多相关文章

  1. 【做题】CF1045(ABH)

    原文链接https://www.cnblogs.com/cly-none/p/9697662.html 题目当然不会做完了,这里只讲有做&会做的. A. Last chance 题意:有\(n ...

  2. HDU-1041-Computer Transformation,大数递推,水过~~

                                                                                  Computer Transformatio ...

  3. 1393 0和1相等串 51nod

    1393 0和1相等串 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 给定一个0-1串,请找到一个尽可能长的子串,其中包含的0与1的个数相等. I ...

  4. LOJ 3184: 「CEOI2018」斐波那契表示法

    题目传送门:LOJ #3184. 题意简述: 题目说得很清楚了. 题解: 首先需要了解「斐波那契数系」为何物. 按照题目中定义的斐波那契数列 \(F_n\),可以证明,每个非负整数 \(n\) 都能够 ...

  5. 【USACO 3.1】Contact(01子串按出现次数排序)

    题意:给你一个01字符串,将长度为a到b之间(包含a.b)的子串按照出现次数排序.注意输入输出格式 题解:01子串对应一个二进制,为了区别11和011这样的不同子串,我们把长度也记录下来,官方题解是在 ...

  6. 2019牛客暑期多校赛(第三场)B-求01串中的最长01数量相等的子串和子序列

    https://ac.nowcoder.com/acm/contest/883/B 首先先把0所在的位置变-1,1所在位置变1,然后统计一个前缀和,用sum[i]表示. 那么如果从起点开始的话只要满足 ...

  7. Java实现固定长度得01子串

    固定位数得01子串 Description 对于长度为n的一个01串,每一位都可能是0或1,一共有2 ^n 种可能.请按从小到大的顺序输出这2^n种01串. Input 包含多组数据,每组数据占一行, ...

  8. 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串

    1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...

  9. 最长相同01数的子串(map搞搞)--牛客第三场 -- Crazy Binary String

    题意: 如题. 或者用我的数组分治也可以,就是有点愚蠢. //#include <bits/stdc++.h> #include <map> #include <iost ...

  10. poj3294 出现次数大于n/2 的公共子串

    Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 13063   Accepted: 3670 Descr ...

随机推荐

  1. 转:linux下面/usr/local和opt目录有何区别

    /usr/local下一般是你安装软件的目录,这个目录就相当于在windows下的programefiles这个目录 /opt这个目录是一些大型软件的安装目录,或者是一些服务程序的安装目录 /opt ...

  2. maven小试牛刀

    Maven是一个采用纯Java编写的开源项目管理工具.Maven采用了一种被称之为project object model (POM)概念来管理项目,所有的项目配置信息都被定义在一个叫做POM.xml ...

  3. VC 6.0 LNK2005 错误 处理

    造成LNK2005错误主要有以下几种情况: 1.重复定义全局变量.可能存在两种情况: A.对于一些初学编程的程序员,有时候会以为需要使用全局变量的地方就可以使用定义申明一下.其实这是错误的,全局变量是 ...

  4. Linux下检查是否安装过某软件包

    1.rpm包安装的,可以用 rpm -qa 看到,如果要查找某软件包是否安装,用 rpm -qa | grep "软件或者包的名字" 2.以deb包安装的,可以用 dpkg -l ...

  5. C#调用java程序

    前言: 最近跟项目组的人合作一个项目,由于之前我用的是java写的一个与android通信的程序,现在另一个同事来编写界面程序,由于C#编写起来比较方便,而我又不想重新写之前java的那段代码,于是需 ...

  6. C++中关于指针初始化和使用NULL的理解

    1.严禁使用未被初始化的指针:C++创建指针的时候,只分配存储地址的内存,并不会分配存储数据的内存,所以指针可能指向任何位置. (1)使用解除运算符(*)之前,一定要对指针初始化,否则若声明的指针刚好 ...

  7. combination-sum-ii(熟悉下Java排序)

    代码还是这一块代码,但是还是写的很慢.. 其中用到了Java对 List的排序.查了很久,发现使用 Collections.sort 很方便. 另外对结果的去重,使用了 Java的HashSet. h ...

  8. POJ 1753 Flip Game (高斯消元 枚举自由变元求最小步数)

    题目链接 题意:4*4的黑白棋,求把棋全变白或者全变黑的最小步数. 分析:以前用状态压缩做过. 和上题差不多,唯一的不同是这个终态是黑棋或者白棋, 但是只需要把给的初态做不同的两次处理就行了. 感觉现 ...

  9. UWP:本地应用数据

    获取应用的设置和文件容器 使用 ApplicationData.LocalSettings 属性可以获取 ApplicationDataContainer 对象中的设置. 注意:每个设置的名称最长可为 ...

  10. ios9下ionic框架报[$rootScope:infdig] 10 $digest() iterations reached. Aborting!的解决办法

    升级ios9后,ionic开发的app会报[$rootScope:infdig] 10 $digest() iterations reached. Aborting!的错误,加上一个patch就可以解 ...