【问题标题】:How to solve the ransom note problem functionally如何在功能上解决赎金问题
【发布时间】:2020-11-19 02:36:59
【问题描述】:

编写一个函数,给出一个字母列表what和一个单词,如果单词可以使用列表中的字母拼写,则返回true,否则返回false。例如像

这样的列表
['a';'b';'d';'e';'a']

还有这个词

bed

函数应该返回 true。 如果单词是bbed,它也应该返回false,因为列表中只有一个b

这很容易通过在 for 循环中改变字典的状态来强制完成,但是如何在不改变的情况下以更实用的风格来做到这一点?

这是我做的命令式版本:

open System.Collections.Generic

let letters = new Dictionary<char,int>()
[ ('a', 2); ('b', 1); ('c', 1); ('e', 1) ] |> Seq.iter letters.Add

let can_spell (word : string) =
    let mutable result = true
    for x in word do
        if letters.ContainsKey x && letters.[x] > 0 then
            let old = letters.[x]
            letters.[x] <- old - 1
        else
            result <- false
    done
    result

【问题讨论】:

  • 这很简单。每次需要重新分配时,不要使用可变变量调用函数。如果您事先不知道函数调用的数量,请使用递归。

标签: functional-programming f#


【解决方案1】:

您可以使用 2 个字典来跟踪单词和现有字母的字母计数,然后检查字母计数是否大于单词字母计数:

let contains (word:string)(letters:IDictionary<char,int>) = 
    let w = word
            |>Seq.countBy id
            |>dict

    w.Keys
    |>Seq.map(fun k-> letters.ContainsKey k && letters.[k] >= w.[k])
    |>Seq.reduce(&&)

你可以这样使用它

let letters = 
    [ ('a', 2); ('b', 1); ('c', 1); ('e', 1); ('d', 1)] 
    |> dict

contains "bed" letters // True

【讨论】:

    【解决方案2】:

    我会这样做:

    let can_spell2 letters word =
        let uniqueLettersCount =    //group unique letters from words and count them
            word |> Seq.groupBy id
            |> Seq.map (fun (l,s) -> l,Seq.length s)
        
        uniqueLettersCount          //keep taking the sequence until you don't find a key or the key count is below the unique letter number
        |> Seq.takeWhile (fun (c,n) ->
            match Map.tryFind c letters with
            | Some n' -> if n' >= n then true else false
            | None -> false)
        |> fun s -> if Seq.length s = Seq.length uniqueLettersCount then true else false //if takeWhile didn't stop, the word is allowed
    

    编辑:

    使用示例:

    let letters = ['a',2;'b',1;'c',1;'e',1] |> Map.ofList
    
    can_spell2 letters "aab" //true
    can_spell2 letters "aaba" //false
    can_spell2 letters "bf" //false
    can_spell2 letters "ecaba" //true
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-21
      相关资源
      最近更新 更多