你有一个包含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)方法很简单,但大型阵列需要花费大量时间。有人能建议一种有效的方法来解决这个问题吗
答案 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