看到有这么道算法题在博客园讨论,算法eaglet邀月都已经设计出来了,花了点时间读了下,学到点东西顺便记录下来吧。

题目是从1...n的数列中,找出总和为n的连续子数列。

这里先设好算法中需要用到的关键变量:

  • s:目标子数列的第一个元素
  • k:目标子数列的长度

那么目标子数列可以表示为(s, k)

1. naive算法(n^2)

最笨的,但是最容易的想到的方法,就是穷举所有的子数列:

for s = 1 to n
for k = 1 to n-s+1
if sum(s, k) == n
output(s, k)

复杂度为:n + (n-1) + (n-2) + (n-3).... = n(n-1)/2

所以,其复杂度是O(n^2)

2. 用二分法改进的naive算法 (nlog2n)

我们需要充分利用输入的特性,这里,原始数列的一个很明显的特点就是有序,而利用有序数列提高效率的最常用方法就是二分法。这里我们可以注意到,针对某个子数列起始点s,我们没有必要逐个长度的去求和判断,而是利用其有序的性质,先求(s, (n+s)/2)的和。如果等于n则输出,如果大于n,则数列结尾在前半段,否则在后半段:


for s = 1 to n
  low = s
  high = n
  while low < high
    mid = (low + high)/2
    sum = sum(s, mid)
    if sum == n
output(s, mid)
    else if(sum > n)
high = mid
    else
low = mid

很明显,此算法复杂度为O(nlog2n)

3. 利用规律s*k <= n而设计的算法 (nlnn)

我们知道,s是目标子数列的第一个元素,也是最小的元素,所以必然有sum(s,k) >= s*k, 也就是n>=s*k, 也就是k <= n/s,于是算法可以写成:

for s = 1 to n
  for k = 1 to n/s
    if sum(s, k) == n
output(s, k);

此处,其复杂度并不是显而易见,但稍加分析:

复杂度 = n + n/2 + n/3 + n/4 + ... + n/n = n (1 + 1/2 + 1/3 + 1/4 + .. + 1/n),可以注意到,括号中的部分是一个调和级数,其和为lnn。

于是,此算法的复杂度为 O(nlnn),比算法2稍佳,因为lnn的底数要稍大些。

4. 利用规律s*k = n-k(k-1)/2而设计的算法(sqrt(n))

我们知道,对于子数列求和,其公式为:

n = k(s+ (s+k-1))/2 = s*k + k(k-1)/2

得出:

s*k = n - k(k-1)/2

由这个公式我们可以得到两点信息:

  • 1*k <= s*k = n-k(k-1)/2,推出n-k(k-1)/2 >= k
  • 如果n-k(k-1)/2能够整除k,则k是目标子数列的长度,而起始点可以由公式算出:s = (n-k(k-1)/2)/k

于是,算法就可以以k为变量递增,以n-k(k-1)/2 >= k为限制条件:


k = 1
v = n-k(k-1)/2
while v >= k
  if v % k == 0
output(v/k, k) // 如果能整除,则找到解,并且起始点为v/k
  k++
  v = n-k(k-1)/2

分析复杂度,我们只需关注k的变化,k是从1递增到某个数结束,关键是如何求这个截止的k。

我们的循环结束条件是:

n-k(k-1)/2 >= k

化简得到:

k^2 + k <= 2n

k^2 <=  2n - k

因为k > 0,于是有

k^2 < 2n

k < sqrt(2n)

所以,这个截止的k就应该是sqrt(2n)或者略小于它

到这里,就不难看出其算法复杂度为O(sqrt(n)) - 略去常数因子和低阶函数

寻找总和为n的连续子数列之算法分析的更多相关文章

  1. javaScript 连续子数列最大和

    <!DOCTYPE html> <html> <head> <title></title> <meta charset=utf-8&g ...

  2. 力扣 - 剑指 Offer 42. 连续子数组的最大和

    题目 剑指 Offer 42. 连续子数组的最大和 思路1(分析数组的规律) 我们可以从头到尾逐个累加,若之前的累加和小于0,那就从丢弃之前的累加,从当前开始重新累加,同时在遍历过程中比较记录下最大值 ...

  3. 最大连续子数组问题2-homework-02

    1) 一维数组最大连续子数组 如第homework-01就是一维数组的最大子数组,而当其首位相接时,只需多考虑子数组穿过相接的那个数就行了! 2)二维数组 算法应该和第一次的相似,或者说是将二维转化为 ...

  4. Java课程课后作业190315之最大连续子数组(二维数组版)

    ,, 在本周的课堂上,老师再一次提高了要求,将一维数组升级成为了二维数组,然后求出块状的连续子数组. 一开始还想着借鉴之前球一维数组的O(n)的算法,后来还是没有找到头绪,舍友讲了自己的办法,但是没有 ...

  5. 连续子数组和的最大值plus

    package wodeshiyao; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStre ...

  6. UVALive 3938 - "Ray, Pass me the dishes!" - [最大连续子列和+线段树]

    题目链接:https://cn.vjudge.net/problem/UVALive-3938 参考刘汝佳书上说的: 题意: 给出一个长度为n的序列, 再给出m个询问, 每个询问是在序列 $[a,b] ...

  7. leetcode面试题42. 连续子数组的最大和

      总结一道leetcode上的高频题,反反复复遇到了好多次,特别适合作为一道动态规划入门题,本文将详细的从读题开始,介绍解题思路. 题目描述示例动态规划分析代码结果 题目   面试题42. 连续子数 ...

  8. Java实现 LeetCode 581 最短无序连续子数组(从两遍搜索找两个指针)

    581. 最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: ...

  9. 剑指Offer面试题:28.连续子数组的最大和

    一.题目:连续子数组的最大和 题目:输入一个整型数组,数组里有正数也有负数.数组中一个或连续的多个整数组成一个子数组.求所有子数组的和的最大值.要求时间复杂度为O(n).例如输入的数组为{1,-2,3 ...

随机推荐

  1. 【BZOJ1345】[Baltic2007]序列问题Sequence 贪心+单调栈

    [BZOJ1345][Baltic2007]序列问题Sequence Description 对于一个给定的序列a1, …, an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和a ...

  2. OSI模型第三层网络层-初识路由协议

    1.路由协议: 顾名思义就是路由器所使用的协议. 分类: (1)按照作用范围分类,IGP(类型)内部网关协议(rip,ospf,isis),EGP(类型)边界路由协议(bgp) 把互联网比作整个世界土 ...

  3. JAVA NIO 简介 (netty源码死磕1.1)

    [基础篇]netty 源码死磕1.1:  JAVA NIO简介 1. JAVA NIO简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/ ...

  4. jqweui tabbar使用示例

    <!DOCTYPE html> <html class="pixel-ratio-1"> <head> <meta http-equiv= ...

  5. 测试站如何最快获取正式站的最新数据: ln -s

    针对静态数据, 比如图片/js等文件, 测试站如何获取最新的呢? ln -s /alidata/www/mysite/uploads /alidata/www/mysite_test/uploads ...

  6. Qt状态机框架(状态机就开始异步的运行了,也就是说,它成为了我们应用程序事件循环的一部分了)

    状态机框架 Qt中的状态机框架为我们提供了很多的API和类,使我们能更容易的在自己的应用程序中集成状态动画.这个框架是和Qt的元对象系统机密结合在一起的.比如,各个状态之间的转换是通过信号触发的,状态 ...

  7. (转)Web Service和WCF的到底有什么区别

    [1]Web Service:严格来说是行业标准,也就是Web Service 规范,也称作WS-*规范,既不是框架,也不是技术. 它有一套完成的规范体系标准,而且在持续不断的更新完善中. 它使用XM ...

  8. 股票技术指标中的VOL,KDJ,MACD,OBV,VR,DMA分别代表什么意思?很关键,谢谢

    http://zhidao.baidu.com/link?url=glKK7n0JUgqgrvfx2Gzd937-5zZg1bC615MwAp0P_mrYDytnMUpjoOQgYU871ny8St1 ...

  9. eclipse新建Maven项目

    1.在eclipse中安装maven插件 2.点击File->new->maven project,出现弹窗后点击next. 接着在弹窗Select an Archetype中,filte ...

  10. 《python基础教程(第二版)》学习笔记 语句/循环/条件(第5章)

    <python基础教程(第二版)>学习笔记 语句/循环/条件(第5章) print 'AB', 123 ==> AB 123 # 插入了一个空格print 'AB', 'CD' == ...