gpt4 book ai didi

algorithm - 构造无限排序列表而不添加重复项

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:51:30 25 4
gpt4 key购买 nike

我对 Haskell 比较陌生,但我正在尝试通过阅读和尝试解决 Project Euler 上的问题来学习这两种方法。我目前正在尝试实现一个函数,该函数采用无限整数列表并返回所述列表中元素成对总和的有序列表。我真的是在寻找针对我所面临的特定问题的解决方案,而不是针对不同策略或方法的建议,但这些也很受欢迎,因为作为一名编码员并不意味着知道如何实现策略,而是选择最佳策略策略可用。

我的方法依赖于遍历无限生成器的无限列表并按顺序检索元素,其中有几个数学属性对实现我的解决方案很有用。

例如,如果我试图获得自然数的成对和序列,这将是我的代码:

myList :: [Integer]
myList = [1..]

myGens :: [[Integer]]
myGens = gens myList
where
gens = \xs -> map (\x -> [x+y|y<-(dropWhile (<x) xs)]) xs

无论使用什么数集,只要是排序的,下面的条件都成立:

  • ∀ i ≥ 0, head (gens xs !! i) == 2*(myList !! i)
  • ∀ i,j,k ≥ 0, l > 0, (((gens xs) !! i) !! j) < (((gens xs) !! i+k) !! j+l)

第二种情况的特例是:

  • ∀ i,j ≥ 0, (((gens xs) !! i) !! j) < (((gens xs) !! i+1) !! j)
  • ∀ i,j ≥ 0, k > 0, (((gens xs) !! i) !! j) < (((gens xs) !! i+k) !! j)

这是我要修改的特定代码:

stride :: [Integer] -> [Int] -> [[Integer]] -> [Integer]
stride xs cs xss = x : stride xs counts streams
where
(x,i) = step xs cs xss
counts = inc i cs
streams = chop i xss

step :: [Integer] -> [Int] -> [[Integer]] -> (Integer,Int)
step xs cs xss = pace xs (defer cs xss)

pace :: [Integer] -> [(Integer,Int)] -> (Integer,Int)
pace hs xs@((x,i):xt) = minim (x,i) hs xt
where
minim :: (Integer,Int) -> [Integer] -> [(Integer,Int)] -> (Integer,Int)
minim m _ [] = m
minim m@(g,i) hs (y@(h,n):ynt) | g > h && 2*(hs !! n) > h = y
| g > h = minim y hs ynt
| 2*(hs !! n) > g = m
| otherwise = minim m hs ynt


defer :: [Int] -> [[a]] -> [(a,Int)]
defer cs xss = (infer (zip cs (zip (map head xss) [0..])))

infer :: [(Int,(a,Int))] -> [(a,Int)]
infer [] = []
infer ((c,xi):xis) | c == 0 = xi:[]
| otherwise = xi:(infer (dropWhile (\(p,(q,r)) -> p>=c) xis))

我正在使用的问题集具有多个不同对产生相同总和的属性。我想要一种同时处理所有重复元素的有效方法,以避免计算所有成对总和达到 N 的成本增加,因为如果 M 是重复元素的数量,则需要进行 M 次测试。

有人有什么建议吗?

编辑:

我独立于建议对代码进行了一些更改,并希望收到有关我的原始代码、修改后的代码和到目前为止的建议的相对效率的反馈。

stride :: [Integer] -> [Int] -> [[Integer]] -> [Integer]
stride xs cs xss = x : stride xs counts streams
where
(x,is) = step xs cs xss
counts = foldr (\i -> inc i) cs is
streams = foldr (\i -> chop i) xss is

step :: [Integer] -> [Int] -> [[Integer]] -> (Integer,[Int])
step xs cs xss = pace xs (defer cs xss)

pace :: [Integer] -> [(Integer,Int)] -> (Integer,[Int])
pace hs xs@((x,i):xt) = minim (x,(i:[])) hs xt
where
minim :: (Integer,[Int]) -> [Integer] -> [(Integer,Int)] -> (Integer,[Int])
minim m _ [] = m
minim m@(g,is@(i:_)) hs (y@(h,n):ynt) | g > h && 2*(hs !! n) > h = (h,[n])
| g > h = minim (h,[n]) hs ynt
| g == h && 2*(hs !! n) > h = (g,n:is)
| g == h = minim (g,n:is) hs ynt
| g < h && 2*(hs !! n) > g = m
| g < h = minim m hs ynt

此外,我遗漏了 inc 的代码和 chop :

alter :: (a->a) -> Int -> [a] -> [a]
alter = \f -> \n -> \xs -> (take (n) xs) ++ [f (xs !! n)] ++ (drop (n+1) xs)

inc :: Int -> [Int] -> [Int]
inc = alter (1+)

chop :: Int -> [[a]] -> [[a]]
chop = alter (tail)

最佳答案

我将提出一个使用无限 pairing heap 的解决方案.我们将对每个构造的元素进行对数开销,但是 no one knows how to do better (在具有基于比较的方法和实数的模型中)。

第一段代码只是标准配对堆。

module Queue where
import Data.Maybe (fromMaybe)

data Queue k = E
| T k [Queue k]
deriving Show

fromOrderedList :: (Ord k) => [k] -> Queue k
fromOrderedList [] = E
fromOrderedList [k] = T k []
fromOrderedList (k1 : ks'@(k2 : _ks''))
| k1 <= k2 = T k1 [fromOrderedList ks']

mergePairs :: (Ord k) => [Queue k] -> Queue k
mergePairs [] = E
mergePairs [q] = q
mergePairs (q1 : q2 : qs'') = merge (merge q1 q2) (mergePairs qs'')

merge :: (Ord k) => Queue k -> Queue k -> Queue k
merge (E) q2 = q2
merge q1 (E) = q1
merge q1@(T k1 q1's) q2@(T k2 q2's)
= if k1 <= k2 then T k1 (q2 : q1's) else T k2 (q1 : q2's)

deleteMin :: (Ord k) => Queue k -> Maybe (k, Queue k)
deleteMin (E) = Nothing
deleteMin (T k q's) = Just (k, mergePairs q's)

toOrderedList :: (Ord k) => Queue k -> [k]
toOrderedList q
= fromMaybe [] $
do (k, q') <- deleteMin q
return (k : toOrderedList q')

请注意 fromOrderedList 接受无限列表。我认为这在理论上可以通过假装无限的后代列表“及时”有效地合并来证明这一点。这感觉就像纯函数式数据结构的文献中应该有的东西,但我会偷懒,现在不看。

函数 mergeOrderedByMin 更进一步,合并了一个可能无限的队列列表,其中每个队列中的最小元素是非递减的。我不认为我们可以重用 merge,因为 merge 似乎不够懒惰。

mergeOrderedByMin :: (Ord k) => [Queue k] -> Queue k
mergeOrderedByMin [] = E
mergeOrderedByMin (E : qs') = mergeOrderedByMin qs'
mergeOrderedByMin (T k q's : qs')
= T k (mergeOrderedByMin qs' : q's)

下一个函数从排序列表中删除重复项。它在 m09 建议的库中,但为了完整起见,我将在此处定义它。

nubOrderedList :: (Ord k) => [k] -> [k]
nubOrderedList [] = []
nubOrderedList [k] = [k]
nubOrderedList (k1 : ks'@(k2 : _ks''))
| k1 < k2 = k1 : nubOrderedList ks'
| k1 == k2 = nubOrderedList ks'

最后,我们把它们放在一起。我将以正方形为例。

squares :: [Integer]
squares = map (^ 2) [0 ..]

sumsOfTwoSquares :: [Integer]
sumsOfTwoSquares
= nubOrderedList $ toOrderedList $
mergeOrderedByMin
[fromOrderedList (map (s +) squares) | s <- squares]

关于algorithm - 构造无限排序列表而不添加重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23345835/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com