找到可以表示为数组的三个不同元素之和的所有数字

时间:2017-01-21 14:06:22

标签: java c++ dynamic-programming

你有一个包含N个不同正整数的数组A.您还有一个空集S.您的任务是添加尽可能多的整数来设置S.如果可以将整数表示为数组A的三个不同元素的总和,则可以将整数添加到S中,并且已经不存在集合S.

示例 - 如果N = 5,则数组包含2,4,6,8,9。 然后该集合包含9个元素 - > 12,14,15,16,17,18,19,21,23

O(n ^ 3)方法很简单,但大型阵列需要花费大量时间。有人能建议一种有效的方法来解决这个问题吗

1 个答案:

答案 0 :(得分:1)

不确定我的解决方案是否实际上比蛮力方法更快(期待咯咯和畏缩)。但是,我的解决方案使用动态编程...我认为:)

基本思想是问题的解决方案(N,1)是微不足道的。输入数组中每个1元组值的总和就是输入数组。

问题的解决方案(N,M)可以使用问题的解决方案(N,M-1),只需映射(N,M-1)解决方案中的所有元素,看起来像{ {1}}。现在,尚未在(N,M-1)解的特定元素中使用的所有索引需要与(N,M-1)解中的每个键以及(N,M)的值的总和组合。 -1)解决方案+未使用索引的值创建(N,M)解决方案的元素。

在这里我们有递归。我们对"更简单"的记忆结果(N,M-1)解决方案,我们用它来解决(N,M)。在此,我们采用了动态编程方法。 (递归+ memoization =动态编程)。

在我目前尝试学习的语言(Haskell)中,我想出了这个实现(很多人认为这很丑陋;)

Map [Int] Int

根据大众的需求,这里的C ++版本......东西:)

import Data.Array
import Data.List
import qualified Data.Map.Strict as Map


type Lut = Map.Map [Int] Int

foo :: Array Int Int -> Int -> Int -> Lut
-- This is our trivial base case. Create a map for the (N,1) case.
-- "input ! i" means what other languages would write as input[i].
foo input n 1 = Map.fromList [([i],input ! i) | i <- [1..n]]
-- This is the general case, which uses recursion.
foo input n m =
    (Map.fromList . fixKeys . concat . fmap sums) (Map.keys lut)
    where 
        lut :: Lut
        -- Here, the recursion happens. (lut stands for LookUp Table)
        lut = foo input n (m-1)
        all = [1..n]
        sums k =
            -- Here we use our (N,M-1) data to create the output
            -- for this recursion step. 
            -- (forall unused element indices do input[i] + lut[k])
            fmap (\(i,k) -> (i:k,input ! i + query k) ) unused
            where 
                -- The \\ means: difference. 
                -- All indices minus the indices used in a key of a (N,M-1) 
                -- element.
                unused = fmap (\i -> (i,k)) (all \\ k)

        query k =
            case Map.lookup k lut of
                Just v -> v
                Nothing -> error "key cannot not be in the map!"
        -- Remove duplicates (e.g. [1,2,3] and [1,3,2]) by sorting them.
        fixKeys l =
            fmap (\(k,v) -> (sort k,v)) l




to1BasedArray l = listArray (1,length l) l

raw = [2, 4, 6, 8, 9]
input = to1BasedArray raw 

output = foo input (length raw) 3