zoukankan      html  css  js  c++  java
  • 【转】【算法学习】最大子串问题

    原文自:http://vistb.net/2011/07/max-subarray-problem/

    今天遇到了这个问题,与大家再次分享。

    今天在看《算法导论》时谈到了最大子串问题,书中共提到了3种算法,时间复杂度依次是O(n^2),O(nlogn)和 O(n)。感觉挺有意思的,写出来分享一下。

    定义:最大子串问题(maximum sub-array problem)

    最大子串问题,又称为最大连续子串问题,是指给出一个长度为n的整数数组A,然后要求给出其中和值最大的连续子数组。也即,求出MAX(SUM(A[i...j])),其中1 ≤ i ≤ j ≤ n。

    解法一:穷举(brute force)

    第一种方法,也是最笨的办法,就是穷举。将所有可能的i、j组合穷举,选出其中SUM(A[i...j])最大的即可。很明显,由于可能的组合数有C(n,2)=O(n^2)个,算法的复杂度也为O(n^2)。

    解法二:分治法(divide and conquer)

    注意到A[1...n]的最大子串A[i..j]可能来自于以下三种情况中的一种:

    • 1 ≤ i ≤ j ≤ n/2,也即最大子串出现在原串的左半部分
    • n/2 ≤ i ≤ j ≤ n,也即最大子串出现在原串的右半部分
    • 1 ≤ i ≤ n/2 ≤ j ≤ n,也即最大子串部分来自原串的最半部分,部分来自原串的右半部分

    因此我们可以分别计算这三种情况下的解,然后将这三个解中最好的一个选出作为整个问题的解。

    针对前两种情况,其实就相当于把问题的规模缩小了(divide)。把求长度为n的数组的最大子串变为求长度最n/2的数组的最大子串。这个规模变小了的问题的解同样可能有三种情况。对其中的前两种情况,我们依然采取细分的方法。可是,这样的细分会有头吗?当然会的,到了最后,我们会得到一个个长度为1的数组,在这种极限情况下,我们就不必考虑三种情况,因为此时的最大子串显然就是这个长度为1的子串自己(conquer)。

    而针对第三种情况,我们采取另一种策略,即不是将问题化为相同的更小规模的问题,而是直接求解。我们首先求出A[i...n/2]使其为A[1...n/2]的最大子串,这里,进行一次遍历即可,时间复杂度为O(n)。同理,我们也可以求出A[n/2...j]使其为A[n/2...n]的最大子串。将这2个最大子串合在一起,就得到了所有会跨越串的中部的子串中的最大子串。

    总结起来,假如使用T(n)代表使用此方法求解大小为n的数组的最大子串问题所消耗的时间,则有:

    • T(n) = 2T(n/2) + O(n),n>1
    • T(1) = O(1),n=1

    不难发现,此时求解整个问题的时间复杂度为O(nlogn)。

    算法的伪代码如下(截取自《算法导论》):

    解法三:动态规划(dynamic programming)

    时间复杂度为O(nlogn)已经是一个比较理想的结果了,但在书后的习题中还提出了另一种基于动态规划的解决思路,可以将时间复杂度降到O(n)。

    具体来说,假如我们已经知道了A[1..j]这个数组的最大子串,那么A[1...(j+1)]的最大子串有可能来自于两种情况,一是其和A[1...j]的最大子串相同,二是A[1...(j+1)]的最大子串具有A[i...(j+1)]的形式,其中1 ≤ i ≤ j+1。针对第二种情况,如果我们已经知道所有尾部为j的子串中的最大子串,我们就可以在常数时间内得到所有尾部为(j+1)的子串中的最大子串。

    基于上面的思想,我们只需从串的最左部开始(此时的最大子串就是串的第一个元素),向右逐渐拓展直到处理完整个串,即可得到最大子串。

    算法的伪代码如下(自己写的,不一定对):

    拓展:K最大子串问题(k maximum sub-array problem)

    在一般的最大子串问题的基础上,我们还可以拓展出K最大子串问题,即如何求出前K个最大子串。这是另一类问题了,此处不再多叙。

    参考资料:

    • 《算法导论(第三版)》第四章第一节:< Introduction to Algorithms (3ed) > Chapter 4 Section 1

    无相关帖子

  • 相关阅读:
    面向对象与原型2---原型
    JavaScript 引用【转】
    面向对象与原型1---创建对象的方法
    匿名函数和闭包(下)
    从输入 URL 到页面加载完的过程中都发生了什么事情?
    匿名函数和闭包(上)
    聚美优品前端开发面试题
    hdoj1045 Fire Net(二分图最大匹配)
    hdoj1180 诡异的楼梯(bfs+奇偶判断)
    hdoj1373 Channel Allocation(极大团)
  • 原文地址:https://www.cnblogs.com/jackyzzy/p/2590483.html
Copyright © 2011-2022 走看看