LeetCode 1061. Lexicographically Smallest Equivalent String in F#

URL

https://leetcode.com/problems/lexicographically-smallest-equivalent-string/

Code

https://github.com/syohex/dotnet-study/blob/master/fsharp/leetcode/problems/1061/main.fsx

open System

let createGraph (s1: string) (s2: string) : Map<char, char list> =
    let rec createGraph' cs1 cs2 acc =
        match cs1, cs2 with
        | [], [] -> acc
        | h1 :: t1, h2 :: t2 ->
            let acc' =
                match Map.tryFind h1 acc with
                | Some (v) -> Map.add h1 (h2 :: v) acc
                | None -> Map.add h1 [ h2 ] acc

            let acc'' =
                match Map.tryFind h2 acc' with
                | Some (v) -> Map.add h2 (h1 :: v) acc'
                | None -> Map.add h2 [ h1 ] acc'

            createGraph' t1 t2 acc''
        | _, _ -> failwith "never reach here"

    createGraph' (s1 |> Seq.toList) (s2 |> Seq.toList) Map.empty

let findSmallestCharacter (c: char) (graph: Map<char, char list>) : char =
    let rec findSmallestCharacter' (c: char) graph visited =
        match Map.tryFind c graph with
        | None -> c, visited
        | Some (nexts) ->
            nexts
            |> List.filter (fun n -> Set.contains n visited |> not)
            |> List.fold
                (fun (acc, vs) n ->
                    let child, vs' = findSmallestCharacter' n graph (Set.add n vs)
                    Math.Min(int acc, int child) |> char, vs')
                (c, visited)

    findSmallestCharacter' c graph Set.empty |> fst


let smallestEquivalentString (s1: string) (s2: string) (baseStr: string) : string =
    let graph = createGraph s1 s2

    let table =
        seq { 'a' .. 'z' }
        |> Seq.fold
            (fun acc c ->
                let minChar = findSmallestCharacter c graph
                Map.add c minChar acc)
            Map.empty

    baseStr
    |> Seq.map (fun c -> Map.find c table)
    |> String.Concat