最大非分段总和

时间:2014-01-09 23:42:40

标签: algorithm functional-programming

我们有一个列表/数组(肯定和否定都是可能的)。

段被定义为数字的连续子序列。例如,[1; -2; 3; 4; 5]是数组,其中一段是[1; -2; 3]或[-2; 3; 4]等。段中的所有数字必须是连续的。

非段被定义为阵列的所有子序列,除了所有段。因此,连续数字在非细分中是可能的,但必须至少有两个不连续的数字。

例如,[1; 3; 4]是非段,[1; -2; 3; 5]也是非段,因为3和5不连续(之间有'4'他们在原始阵列中。)

问题是具有最大金额的非细分市场是什么?


请注意

  1. 数字可以是正面和负面的混合
  2. 这不是http://algorithmsbyme.wordpress.com/2012/07/29/amazon-interview-question-maximum-possible-sum-with-non-consecutive-numbers/Maximum sum of non consecutive elements的问题。在这些问题中,没有数字可以连续,所有数字都是正数。

  3. 这是Pearls of functional algorithm design一书中的问题11,它说有一种线性方式来解决它。

    但我无法理解也找不到线性方式。所以我在这里试试运气。

3 个答案:

答案 0 :(得分:1)

有两种可能性:

  • 最多存在2个非负数,并且在存在2个的情况下,它们是相邻的。

    在这种情况下,我们选择最大的一对非相邻数字。这可以通过找到最大数量和最大非相邻数字的总和,然后是两个相邻数字的总和,在线性时间内完成。

    示例:

    Input: [-5, -10, -6, -2, -1, -2, -10]
    

    最大的数字是-1,因此我们将-1与最大的非相邻数字-5相加,得到-6。然后我们还尝试-2-2,给出-4。因此,最大的非细分总和为-4

  • 至少存在两个非相邻的非负数。

    我们选择所有正数。如果最大数字为零(即没有正数),则选择所有零。

    如果所有选中的号码都是连续的,请尝试:

    • 排除不在其中一端的最小的一个。

    • 包括与拾取的数字不相邻的最大(即最接近0)非正数(如果存在这样的0,这将是最佳选择)。

    • 反过来,尝试从序列末尾排除数字,然后在其旁边加上非正数(仅当旁边有数字时才这样做。)

      < / LI>

    选择此处的选项,即可获得最大金额。

    显然,所有这些都可以在线性时间内发生。

    示例:

    Input: [-5, -1, 5, 7, 9, 11, -1, -10]
    

    首先,我们选择所有正数 - 5, 7, 9, 11,但它们是连续的。

    因此我们尝试排除最小的非结束号码(7),
    给我们sum(5, 9, 11) = 25

    然后我们尝试包含最大的非邻近负数(-5),
    给我们sum(-5, 5, 7, 9, 11) = 27

    然后我们尝试排除左边缘(5)并在其旁边添加数字(-1),
    给我们sum(-1, 7, 9, 11) = 26

    然后我们尝试排除右边缘(11)并在其旁边添加数字(-1),
    给我们sum(-1, 5, 7, 9) = 20

    显然,最高金额为27

    请注意我们如何通过更改值来使任何条件成为最大总和,因此需要所有条件。

答案 1 :(得分:1)

这是一个更适合函数式编程习惯的解决方案。可以想象一个四态有限自动机接受具有两个不相邻的1的弦。

       0         1         0         0,1
      ___       ___       ___        ___
     v  /  1   v  /  0   v  /  1    v  /
---> (q0) ---> (q1) ---> (q2) ---> ((q3))

下面的Haskell程序主要是一次扫描一个数字,并记住可以通过选择产生的最大值,当被解释为0和1时,将自动机置于状态q1segmentEndingHere),状态q2segmentNotEndingHere)或州q3nonSegment)。这种技术是一个大锤,可以解决许多关于序列优化的问题。

maximumNonSegmentSum :: (Num a, Ord a) => [a] -> Maybe a
maximumNonSegmentSum = mnss Nothing Nothing Nothing
  where  
        (^+) :: (Num a) => a -> Maybe a -> Maybe a
        (^+) = liftM . (+)

        mnss ::
             (Num a, Ord a) => Maybe a -> Maybe a -> Maybe a -> [a] -> Maybe a
        mnss segmentEndingHere segmentNotEndingHere nonSegment xs
          = case xs of
                [] -> nonSegment
                x : xs'
                  -> mnss ((x ^+ segmentEndingHere) `max` Just x)
                       (segmentNotEndingHere `max` segmentEndingHere)
                       (((x `max` 0) ^+ nonSegment) `max` (x ^+ segmentNotEndingHere))
                       xs'

答案 2 :(得分:0)

取所有正数。如果它们形成一个段,请检查是否可以添加与其不相邻的内容。还要检查一下你是否可以在中间挑选一些东西。还要检查你是否可以选择一个结尾并输入旁边的数字。要证明其中一个导致最佳非细分市场并不难。