Procházet zdrojové kódy

Day6 with better algorithm

main
Jens Kadenbach před 2 roky
rodič
revize
001ffc6789
2 změnil soubory, kde provedl 28 přidání a 25 odebrání
  1. 21
    18
      src/Day6.hs
  2. 7
    7
      test/Day6Spec.hs

+ 21
- 18
src/Day6.hs Zobrazit soubor

@@ -1,32 +1,35 @@
1 1
 module Day6 (
2 2
   findEnd,
3 3
   findStart,
4
-  isUnique,
5 4
   day6
6 5
 ) where
7 6
 
8
-findMarker :: Int -> String -> Maybe Int
9
-findMarker windowSize = findMarker' 0 ""
10
-  where
11
-  findMarker' :: Int -> String -> String -> Maybe Int
12
-  findMarker' offset window  []
13
-    | isUnique window && length window == windowSize = Just offset
14
-    | otherwise = Nothing
15
-  findMarker' offset window (c:cs)
16
-    | length window < windowSize = findMarker' (offset + 1) (c:window) cs
17
-    | not (isUnique window) = findMarker' (offset + 1) (c:init window) cs
18
-    | isUnique window = Just offset
19
-    | otherwise = Nothing
7
+import qualified Data.Sequence as S
8
+import Data.Sequence (Seq (..), (|>))
20 9
 
21 10
 findStart :: String -> Maybe Int
22
-findStart = findMarker 14 
11
+findStart = findUniqueSubstring 14
23 12
 
24 13
 findEnd :: String -> Maybe Int
25
-findEnd = findMarker 4
14
+findEnd = findUniqueSubstring 4
26 15
 
27
-isUnique :: (Eq a) => [a] -> Bool
28
-isUnique [] = True
29
-isUnique (c:cs) = c `notElem` cs && isUnique cs
16
+findUniqueSubstring :: Int -> String -> Maybe Int
17
+findUniqueSubstring size input
18
+ | length input < size = Nothing -- imposible to find a substring because input is too small
19
+ | otherwise = find 0 S.empty $ S.fromList input
20
+  where
21
+    find :: Int -> Seq Char -> Seq Char -> Maybe Int
22
+    find _ _ Empty = Nothing
23
+    find off window (r :<| rs)
24
+      = case S.elemIndexL r window of -- is new element in window?
25
+        Nothing -> if S.length window == size -1            -- Element not found, but is our window large nough?
26
+                      then Just nextOff                     -- Large enough, we got a winner!
27
+                      else find nextOff enlargedWindow rs   -- Not large enough, push new element to the end of the window
28
+        Just i -> find nextOff  (removeConflict (i + 1)) rs -- continue after clearing window
29
+      where
30
+        nextOff = off + 1
31
+        enlargedWindow = window |> r
32
+        removeConflict i = S.drop i enlargedWindow
30 33
 
31 34
 day6 :: IO ()
32 35
 day6 = do

+ 7
- 7
test/Day6Spec.hs Zobrazit soubor

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

Načítá se…
Zrušit
Uložit