Day6 with better algorithm
This commit is contained in:
39
src/Day6.hs
39
src/Day6.hs
@@ -1,32 +1,35 @@
|
||||
module Day6 (
|
||||
findEnd,
|
||||
findStart,
|
||||
isUnique,
|
||||
day6
|
||||
) where
|
||||
|
||||
findMarker :: Int -> String -> Maybe Int
|
||||
findMarker windowSize = findMarker' 0 ""
|
||||
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
|
||||
import qualified Data.Sequence as S
|
||||
import Data.Sequence (Seq (..), (|>))
|
||||
|
||||
findStart :: String -> Maybe Int
|
||||
findStart = findMarker 14
|
||||
findStart = findUniqueSubstring 14
|
||||
|
||||
findEnd :: String -> Maybe Int
|
||||
findEnd = findMarker 4
|
||||
findEnd = findUniqueSubstring 4
|
||||
|
||||
isUnique :: (Eq a) => [a] -> Bool
|
||||
isUnique [] = True
|
||||
isUnique (c:cs) = c `notElem` cs && isUnique cs
|
||||
findUniqueSubstring :: Int -> String -> Maybe Int
|
||||
findUniqueSubstring size input
|
||||
| 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 = do
|
||||
|
||||
@@ -2,21 +2,21 @@ module Day6Spec (spec) where
|
||||
|
||||
import Test.Hspec
|
||||
import Day6
|
||||
import qualified Data.Sequence as S
|
||||
|
||||
spec :: Spec
|
||||
spec =
|
||||
describe "Day6" $ do
|
||||
describe "Part1" $ do
|
||||
it "finds unique lists" $ do
|
||||
isUnique "abc" `shouldBe` True
|
||||
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 just after the beginning" $ do
|
||||
findEnd "aabcd" `shouldBe` Just 5
|
||||
it "finds the marker in the beginning" $ do
|
||||
findEnd "abcd" `shouldBe` Just 4
|
||||
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
|
||||
findEnd "mjqjpqmgbljsphdztnvjfqwrcgsmlb"`shouldBe` Just 7
|
||||
findEnd "bvwbjplbgvbhsrlpgdmjqwftvncz" `shouldBe` Just 5
|
||||
|
||||
Reference in New Issue
Block a user