Swift Anagram 检查器(字符串-字谜检查器:两个小写字符串如何比较他们包含的字符种类和数量是否相同?)

Swift Anagram 检查器(字符串-字谜检查器)

字谜检查器怎么检查两个顺序无所谓(不同)的字符串,它们的内容是否都包含相同的字符?

举例说明:两个小写字符串 str1 和 str2 比较他们包含的字符种类和数量是否相同?
如 输入“abc”,“cba” 输出YES
如 输入“abcc”,“cbca” 输出YES
如 输入 “abcc”,“abc” 输出NO
如 输入 “abc”,“abd” 输出NO
如 输入 “abccc”,“abbcc” 输出NO
这是一道iOS笔试题,遇到记录一下

Anagram 检查器具体实现

为了衡量性能,我将使用不同的变体从 50,000 多个单词的数组中找到给定单词的字谜。

// Variant 1: Sorting of Character
// Measured time: 30.46 s
func anagramCheck1(a: String, b: String) -> Bool {
    return a.characters.sorted() == b.characters.sorted()
}

这本质上是接受答案的解决方案,用 Swift 3 语法编写。这很慢,因为 Swift 的 String 与 NSString 不同,它是基于 Character 的,它可以正确处理 Unicode 字符。

一个更有效的解决方案是利用 NSCountedSet 类,它允许我们将字符串表示为一组字符,每个字符都有自己的计数。如果两个字符串映射到同一个 NSCountedSet,则它们是字谜。注意:检查字符串长度作为先决条件使实现总是更有效。

// Variant 2: NSCountedSet of Character
// Measured time: 4.81 s
func anagramCheck2(a: String, b: String) -> Bool {
    guard a.characters.count == b.characters.count else { return false }
    let aSet = NSCountedSet()
    let bSet = NSCountedSet()
    for c in a.characters {
        aSet.add(c)
    }
    for c in b.characters {
        bSet.add(c)
    }
    return aSet == bSet
}

更好但不是很好。在这里,“罪魁祸首”之一是使用原生 Swift Character 类型(来自 Swift 的 String)。回到旧的 Objective-C 类型(NSString 和 unichar)可以让事情变得更有效率。

// Variant 3: NSCountedSet of unichar
// Measured time: 1.31 s
func anagramCheck3(a: String, b: String) -> Bool {
    let aString = a as NSString
    let bString = b as NSString
    let length = aString.length
    guard length == bString.length else { return false }
    let aSet = NSCountedSet()
    let bSet = NSCountedSet()
    for i in 0..

使用 NSCountedSet 很好,但是在我们比较两个 NSCountedSet 对象之前,我们会完全填充它们。一个有用的替代方法是只为两个字符串中的一个完全填充 NSCountedSet,然后,当我们为另一个字符串填充 NSCountedSet 时,如果另一个字符串包含在第一个字符串的 NSCountedSet 中找不到的字符,我们会提前失败细绳。

// Variant 4: NSCountedSet of unichar and early exit
// Measured time: 1.07 s
func anagramCheck4(a: String, b: String) -> Bool {
    let aString = a as NSString
    let bString = b as NSString
    let length = aString.length
    guard length == bString.length else { return false }
    let aSet = NSCountedSet()
    let bSet = NSCountedSet()
    for i in 0..= aSet.count(for: c) {
            return false
        }
        bSet.add(c)
    }
    return true
}

这是我们将获得的最佳时机(使用 Swift)。但是,为了完整起见,让我再讨论一个此类变体。

下一个替代方案利用 [unichar: Int] 类型的 Swift Dictionary 来存储每个字符的重复次数,而不是 NSCountedSet。它比前两个变体稍慢,但我们可以稍后重用它以获得更快的实现。


// Variant 5: counting repetitions with [unichar:Int]
// Measured time: 1.36
func anagramCheck5(a: String, b: String) -> Bool {
    let aString = a as NSString
    let bString = b as NSString
    let length = aString.length
    guard length == bString.length else { return false }
    var aDic = [unichar:Int]()
    var bDic = [unichar:Int]()
    for i in 0.. aDic[c] ?? 0 {
            return false
        }
        bDic[c] = count
    }
    return true
}

请注意,使用 NSCountedSet 的 vanilla Objective-C 实现(对应于 Variant 3)比所有以前的版本快很多。

// Variant 6: Objective-C and NSCountedSet
// Measured time: 0.65 s
- (BOOL)anagramChecker:(NSString *)a with:(NSString *)b {
    if (a.length != b.length) {
        return NO;
    }
    NSCountedSet *aSet = [[NSCountedSet alloc] init];
    NSCountedSet *bSet = [[NSCountedSet alloc] init];
    for (int i = 0; i < a.length; i++) {
        [aSet addObject:@([a characterAtIndex:i])];
        [bSet addObject:@([b characterAtIndex:i])];
    }
    return [aSet isEqual:bSet];
}

我们可以改进之前尝试的另一种方法是观察,如果我们需要找到给定单词的字谜,我们不妨认为该单词是固定的,因此我们可以构建相应的结构(NSCountedSet,Dictionary,… …) 这个词只有一次。

// Finding all the anagrams of word in words
// Variant 7: counting repetitions with [unichar:Int]
// Measured time: 0.58 s
func anagrams(word: String, from words: [String]) -> [String] {
    let anagrammedWord = word as NSString
    let length = anagrammedWord.length
    var aDic = [unichar:Int]()
    for i in 0.. aDic[c] ?? 0 {
                return false
            }
            bDic[c] = count
        }
        return true
    }
    return foundWords
}

现在,在前面的变体中,我们使用了 [unichar:Int] 字典。这证明比使用 NSCountedSet 的 unichar 更有效,无论是提前退出(0.60 秒)还是不提前退出(0.87 秒)。

参考文献

Swift Anagram 检查器

你可能感兴趣的:(iOS开发-Swift,swift,ios,objective-c)