subsequences of length n from list performance

前端 未结 4 566
借酒劲吻你
借酒劲吻你 2020-12-05 22:07

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          


        
4条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-05 22:41

    I assume that map (x:) gives a problem performance wise

    No. map is coded efficiently and runs in linear time, no problems here.

    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 ++ [[]])
    

    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.

    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)
    

提交回复
热议问题