I’m having a hard time passing the last group of tests of Kattis’ Nafnagift, in which you should find the shortest common supersequence of two strings.
I tried implementing memoization using advice from one of Brent Yorgey’s blog posts about automatic memoization but it is not enough, although memoization noticeably sped up my solution.
Here is the full solution. What improvements would you make?
{-# LANGUAGE LambdaCase #-}
module Main where
import Control.Arrow ((>>>))
import Control.Monad (join)
import Data.Array (Array, Ix, listArray, (!))
import Data.Bifunctor (bimap)
import Data.Either (isLeft)
import Data.Foldable (maximumBy)
import Data.List (tails)
import Data.Ord (comparing)
main :: IO ()
main = interact $ lines >>> (\[m, n] -> solve (m, n))
solve :: (Eq a) => ([a], [a]) -> [a]
solve (m, n) = map (either id id) $ scs (m, n)
where
rng = ((0, 0), (length m, length n))
is = reverse $ (,) <$> tails m <*> tails n
scs = memo is rng $ \case
(x : xs, y : ys)
| x == y -> Left x : scs (xs, ys)
| otherwise ->
maximumBy
(comparing (length . filter isLeft))
[Right y : scs (x : xs, ys), Right x : scs (xs, y : ys)]
(xs, ys) -> Right <$> xs <> ys
tabulate :: (Ix i) => [a] -> (i, i) -> (a -> e) -> Array i e
tabulate is rng f = listArray rng (map f is)
memo is rng f i = tabulate is rng f ! join bimap length i