Day6 with better algorithm

This commit is contained in:
Jens Kadenbach
2022-12-06 18:14:27 +01:00
parent 95f13675dd
commit 001ffc6789
2 changed files with 28 additions and 25 deletions

View File

@@ -1,32 +1,35 @@
module Day6 ( module Day6 (
findEnd, findEnd,
findStart, findStart,
isUnique,
day6 day6
) where ) where
findMarker :: Int -> String -> Maybe Int import qualified Data.Sequence as S
findMarker windowSize = findMarker' 0 "" import Data.Sequence (Seq (..), (|>))
where
findMarker' :: Int -> String -> String -> Maybe Int
findMarker' offset window []
| isUnique window && length window == windowSize = Just offset
| otherwise = Nothing
findMarker' offset window (c:cs)
| length window < windowSize = findMarker' (offset + 1) (c:window) cs
| not (isUnique window) = findMarker' (offset + 1) (c:init window) cs
| isUnique window = Just offset
| otherwise = Nothing
findStart :: String -> Maybe Int findStart :: String -> Maybe Int
findStart = findMarker 14 findStart = findUniqueSubstring 14
findEnd :: String -> Maybe Int findEnd :: String -> Maybe Int
findEnd = findMarker 4 findEnd = findUniqueSubstring 4
isUnique :: (Eq a) => [a] -> Bool findUniqueSubstring :: Int -> String -> Maybe Int
isUnique [] = True findUniqueSubstring size input
isUnique (c:cs) = c `notElem` cs && isUnique cs | length input < size = Nothing -- imposible to find a substring because input is too small
| otherwise = find 0 S.empty $ S.fromList input
where
find :: Int -> Seq Char -> Seq Char -> Maybe Int
find _ _ Empty = Nothing
find off window (r :<| rs)
= case S.elemIndexL r window of -- is new element in window?
Nothing -> if S.length window == size -1 -- Element not found, but is our window large nough?
then Just nextOff -- Large enough, we got a winner!
else find nextOff enlargedWindow rs -- Not large enough, push new element to the end of the window
Just i -> find nextOff (removeConflict (i + 1)) rs -- continue after clearing window
where
nextOff = off + 1
enlargedWindow = window |> r
removeConflict i = S.drop i enlargedWindow
day6 :: IO () day6 :: IO ()
day6 = do day6 = do

View File

@@ -2,21 +2,21 @@ module Day6Spec (spec) where
import Test.Hspec import Test.Hspec
import Day6 import Day6
import qualified Data.Sequence as S
spec :: Spec spec :: Spec
spec = spec =
describe "Day6" $ do describe "Day6" $ do
describe "Part1" $ do describe "Part1" $ do
it "finds unique lists" $ do it "finds the marker just after the beginning" $ do
isUnique "abc" `shouldBe` True findEnd "aabcd" `shouldBe` Just 5
isUnique "abca" `shouldBe` False
isUnique "cabc" `shouldBe` False
it "finds nothing if nothing is there" $ do
findEnd "abcb" `shouldBe` Nothing
findEnd "abcabcb" `shouldBe` Nothing
it "finds the marker in the beginning" $ do it "finds the marker in the beginning" $ do
findEnd "abcd" `shouldBe` Just 4 findEnd "abcd" `shouldBe` Just 4
findEnd "aabcd" `shouldBe` Just 5 findEnd "aabcd" `shouldBe` Just 5
it "finds nothing if nothing is there" $ do
findEnd "abc" `shouldBe` Nothing
findEnd "abcb" `shouldBe` Nothing
findEnd "abcabcb" `shouldBe` Nothing
it "finds a marker" $ do it "finds a marker" $ do
findEnd "mjqjpqmgbljsphdztnvjfqwrcgsmlb"`shouldBe` Just 7 findEnd "mjqjpqmgbljsphdztnvjfqwrcgsmlb"`shouldBe` Just 7
findEnd "bvwbjplbgvbhsrlpgdmjqwftvncz" `shouldBe` Just 5 findEnd "bvwbjplbgvbhsrlpgdmjqwftvncz" `shouldBe` Just 5