Letters and Numbers


In [1]:
import Data.List
import Data.Char
import Data.Function
import Data.Maybe
import qualified Data.IntMap as IntMap

In [2]:
type State = (IntMap.IntMap (Int, Int), Int)

computeState :: State -> (Int, Char) -> State
computeState (oldMap, oldLevel) (index, c) =
    let
        newLevel = (if isDigit c then succ else pred) oldLevel
        rangeStart = fromMaybe index $ fmap fst $ IntMap.lookup newLevel oldMap
        newMap = IntMap.insert newLevel (rangeStart, index) oldMap
    in
        (newMap, newLevel)

In [3]:
longestSubarray :: String -> String
longestSubarray s =
    let
        levelMap = fst $ foldl' computeState (IntMap.singleton 0 (0, 0), 0) (zip [1..] s)
        (left, right) = minimumBy (compare `on` uncurry (-)) (IntMap.elems levelMap)
    in
        take (right - left) $ drop left s

In [4]:
longestSubarray "AAA7BB88"


"A7BB88"

In [5]:
import Test.QuickCheck

In [6]:
testCountDigitsLetters :: String -> Bool
testCountDigitsLetters s =
    (==) 0 $ sum $ map (\c -> if isDigit c then 1 else -1) (longestSubarray s)

In [7]:
quickCheck testCountDigitsLetters


+++ OK, passed 100 tests.

In [8]:
testSubstringProperty :: String -> Bool
testSubstringProperty s =
    isInfixOf (longestSubarray s) s

In [9]:
quickCheck testSubstringProperty


+++ OK, passed 100 tests.