我是编程新手,F#是我的第一语言。
这是我的代码:
let areAnagrams (firstString: string) (secondString: string) =
let countCharacters (someString: string) =
someString.ToLower().ToCharArray() |> Array.toSeq
|> Seq.countBy (fun eachChar -> eachChar)
|> Seq.sortBy (snd >> (~-))
countCharacters firstString = countCharacters secondString
let testString1 = "Laity"
let testString2 = "Italy"
printfn "It is %b that %s and %s are anagrams." (areAnagrams testString1 testString2) (testString1) (testString2)
这是输出:
Laity和意大利是字谜,这是错误的。
出了什么问题?我应该做些什么改变?
答案 0 :(得分:4)
countCharacters
的实现仅使用第二个元素(每个字符的出现次数)对元组进行排序,但如果有多个字符出现的次数相同,则不会定义顺序。
如果您对两个样本运行countCharacters
函数,则可以看到问题:
> countCharacters "Laity";;
val it : seq<char * int> = seq [('l', 1); ('a', 1); ('i', 1); ('t', 1); ...]
> countCharacters "Italy";;
val it : seq<char * int> = seq [('i', 1); ('t', 1); ('a', 1); ('l', 1); ...]
一种解决方案是只使用Seq.sort
并使用字母代码和出现次数对元组进行排序。
另一个问题是你正在比较两个seq<_>
值并且这不使用结构比较,因此你需要将结果转换为列表或数组(完全评估的内容) :
let countCharacters (someString: string) =
someString.ToLower().ToCharArray()
|> Seq.countBy (fun eachChar -> eachChar)
|> Seq.sort
|> List.ofSeq
请注意,您实际上并不需要Seq.countBy
- 因为如果您只是对所有字符进行排序,它将同样有效(重复的字符将是一个接一个)。所以你可以使用:
let countCharacters (someString: string) =
someString.ToLower() |> Seq.sort |> List.ofSeq
答案 1 :(得分:1)
对两个字符串的字符进行排序为您提供了一个简单的解决方案,但这可能是一个很好的递归示例。
您可以立即排除不同长度的字符串。
您还可以通过将每个迭代替换为空字符串来过滤掉所有出现的char。
let rec areAnagram (x:string) (y:string) =
if x.Lenght <> t.Lenght
then false else
if x.Lenght = 0
then true else
let reply = x.[0].ToString ()
areAnagram
(x.Replace (reply,""))
(y.Replace (reply,""))
上述应该比许多用例的排序更快。
无论如何,我们可以进一步将其转换为快速整数排序,而无需递归和字符串替换
let inline charToInt c =
int c - int '0'
let singlePassAnagram (x:string) =
let hash : int array = Array.zeroCreate 100
x |> Seq.iter (fun c->
hash.[charToInt c] <- (hash.[charToInt c]+1)
)
let areAnagramsFast
(x:string) (y:string) =
if x.Length <> y.Length
then false else
(singlePassAnagram x) =
(singlePassAnagram y)
这是fiddle