问题描述
我实现了这个答案的一个版本https://stackoverflow.com/a/9920425/1261166(我不不知道回答者的意图是什么)
I implemented a version of this answer https://stackoverflow.com/a/9920425/1261166 (I don't know what was intended by the person answering)
sublistofsize 0 _ = [[]]
sublistofsize _ [] = []
sublistofsize n (x : xs) = sublistsThatStartWithX ++ sublistsThatDontStartWithX
where sublistsThatStartWithX = map (x:) $ sublistofsize (n-1) xs
sublistsThatDontStartWithX = sublistofsize n xs
我不确定的是 sublistsThatStartWithX = map (x:) $ sublistofsize (n-1) xs
我假设 map (x:) 给出了一个明智的性能问题,但不确定如何解决它.我已经对 print $ length $ sublistofsize 5 $ primesToTakeFrom 50
I assume that map (x:) gives a problem performance wise, but not sure of how to solve it. I've done profiling on print $ length $ sublistofsize 5 $ primesToTakeFrom 50
COST CENTRE MODULE no. entries %time %alloc %time %alloc
sublistofsize Main 112 4739871 46.9 39.9 96.9 100.0
sublistofsize.sublistsThatDontStartWithX Main 124 2369935 2.2 0.0 2.2 0.0
sublistofsize.sublistsThatStartWithX Main 116 2369935 47.8 60.1 47.8 60.1
我是否以一种好的方式实施了它?有什么更快的方法吗?
Did I implement it in a good way?Are there any faster ways of doing it?
推荐答案
没有.map
被高效编码并在线性时间内运行,这里没有问题.
No. map
is coded efficiently and runs in linear time, no problems here.
但是,您的递归可能是一个问题.你们都在调用 sublistofsize (n-1) xs
和 sublistofsize n xs
,它们 - 给定一个起始列表 sublistofsize m (_:_:ys)
- 确实对术语 sublistofsize (m-1) ys
求值两次,因为它们在不同的递归步骤中没有共享.
However, your recursion might be a problem. You're both calling sublistofsize (n-1) xs
and sublistofsize n xs
, which - given a start list sublistofsize m (_:_:ys)
- does evaluate the term sublistofsize (m-1) ys
twice, as there is no sharing between them in the different recursive steps.
所以我会应用动态规划来获得
So I'd apply dynamic programming to get
subsequencesOfSize :: Int -> [a] -> [[a]]
subsequencesOfSize n xs = let l = length xs
in if n>l then [] else subsequencesBySize xs !! (l-n)
where
subsequencesBySize [] = [[[]]]
subsequencesBySize (x:xs) = let next = subsequencesBySize xs
in zipWith (++) ([]:next) (map (map (x:)) next ++ [[]])
并不是说附加空列表是最漂亮的解决方案,但是您可以看到我如何将 zipWith
与置换列表一起使用,以便使用 next
的结果两次 - 一次直接在长度为 n 的子序列列表中,一次在长度为 n+1 的子序列列表中.
Not that appending the empty lists is the most beautiful solution, but you can see how I have used zipWith
with the displaced lists so that the results from next
are used twice - once directly in the list of subsequences of length n and once in the list of subsequences of length n+1.
在 GHCI 中使用 :set +s
对其进行测试,您会发现这比简单的解决方案要快得多:
Testing it in GHCI with :set +s
, you can see how this is drastically faster than the naive solutions:
*Main> length $ subsequencesOfSize 7 [1..25]
480700
(0.25 secs, 74132648 bytes)
(0.28 secs, 73524928 bytes)
(0.30 secs, 73529004 bytes)
*Main> length $ sublistofsize 7 [1..25] -- @Vixen (question)
480700
(3.03 secs, 470779436 bytes)
(3.35 secs, 470602932 bytes)
(3.14 secs, 470747656 bytes)
*Main> length $ sublistofsize' 7 [1..25] -- @Ganesh
480700
(2.00 secs, 193610388 bytes)
(2.00 secs, 193681472 bytes)
*Main> length $ subseq 7 [1..25] -- @user5402
480700
(3.07 secs, 485941092 bytes)
(3.07 secs, 486279608 bytes)
这篇关于来自列表性能的长度为 n 的子序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!