Skip to content

Instantly share code, notes, and snippets.

@lazamar
Last active January 31, 2020 03:56
Show Gist options
  • Save lazamar/746b73049a83bc0be4c4fcd5a8fbbc6a to your computer and use it in GitHub Desktop.
Save lazamar/746b73049a83bc0be4c4fcd5a8fbbc6a to your computer and use it in GitHub Desktop.
module Lib where
import Data.List (foldr)
-- Complete the highestValuePalindrome function below.
highestValuePalindrome :: String -> Int -> Int -> String
highestValuePalindrome s n changesAllowed =
if changesToMakePalindrome > changesAllowed
then "-1"
else result
where
changesToMakePalindrome = sum $ fmap (uncurry palindromeCost) $ zip [0..] $ take half allStats
-- Cost of transforming a string into a palindrome
palindromeCost ix (_, isEqual) = if isEqual || isMiddleChar ix then 0 else 1
-- After making it a palindrome how many more changes can we make?
extraChanges = changesAllowed - changesToMakePalindrome
result = take firstHalf withNines ++ reverse (take half withNines)
half = n `div` 2
firstHalf = half + n - 2 * half
-- String with as many characters replaced for '9' as possible
withNines = reverse $ snd $ foldr withCosts ((1, 0) , []) $ reverse $ take firstHalf allStats
withCosts stat ((ix, totalCost), list) =
let
cost = nineCost ix stat - palindromeCost ix stat
in
if extraChanges >= totalCost + cost
then ( (ix + 1, totalCost + cost), '9' : list )
else ( (ix + 1, totalCost ), fst stat : list )
-- pair of target letter and whether it is equal on both sides of the string
allStats :: [(Char, Bool)]
allStats = zipWith (\a b -> (max a b, a == b)) s (reverse s)
isMiddleChar ix = odd n && ix == half + 1
-- Number of changes required to convert one character into a nine on both sides of the string
nineCost :: Int -> (Char, Bool) -> Int
nineCost ix (char, isEqual) =
let
cost = if char /= '9'
then 2
else if isEqual
then 0
else 1
in
if isMiddleChar ix
then max 0 (cost - 1)
else cost
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment