如何使用递归定义检查Swift中的回文

时间:2015-12-28 07:39:50

标签: swift recursion palindrome

我喜欢Swift中的许多功能,但使用操作字符串仍然是一个很大的痛苦。

func checkPalindrome(word: String) -> Bool {
    print(word)
    if word == "" {
        return true
    } else {
        if word.characters.first == word.characters.last {
            return checkPalindrome(word.substringWithRange(word.startIndex.successor() ..< word.endIndex.predecessor()))
        } else {
            return false
        }
    }
}

只要字符串的长度为奇数,此代码就会失败。当然我可以这样做,所以块的第一行是if word.characters.count < 2,但是在Swift中有一种方法可以获得子串并轻松检查吗?

更新 我喜欢很多建议,但我想原来的问题可能会有点误导,因为这是一个关于String的问题而不是为函数获得正确的结果。

例如,在Python中,checkPalindrome(word [1:-1])可以很好地用于递归定义,而Swift代码则不那么优雅,因为它需要其他的铃声和口哨声。

12 个答案:

答案 0 :(得分:3)

有时使用前端进行递归可以简化生活。我有时会在最方便使用的参数不是我想要的用户界面时执行此操作。

以下是否满足您的需求?

func checkPalindrome(str: String) -> Bool {
  func recursiveTest(var charSet: String.CharacterView) -> Bool {
    if charSet.count < 2 {
      return true
    } else {
      if charSet.popFirst() != charSet.popLast() {
        return false
      } else {
        return recursiveTest(charSet)
      }
    }
  }
  return recursiveTest(str.characters)
}

答案 1 :(得分:2)

extension String {
    var lettersOnly: String {
        return componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet).joinWithSeparator("")
    }

    var isPalindrome: Bool {
        return String(characters.reverse()).lettersOnly.lowercaseString == lettersOnly.lowercaseString
    }
}

"Dammit I'm Mad".isPalindrome    // true

"Socorram-me subi no onibus em marrocos".isPalindrome   // true

你也可以将你的字符串分解为一个字符数组并迭代它们直到它的一半与它的对应物进行比较:

func checkPalindrome(word: String) -> Bool {
    let chars = Array(word.lettersOnly.lowercaseString.characters)
    for index in  0..<chars.count/2 {
        if chars[index] != chars[chars.count.predecessor() - index] {
            return false
        }
    }
    return true
}

修复范围问题的递归版本无法与endIndex&lt;形成范围的startIndex:

func checkPalindrome<T: StringProtocol>(_ word: T) -> Bool where T.Index == String.Index {
    let word = word.lowercased()
        .components(separatedBy: .punctuationCharacters).joined()
        .components(separatedBy: .whitespacesAndNewlines).joined()
    if word == "" || word.count == 1 {
        return true
    } else {
        if word.first == word.last {
            let start = word.index(word.startIndex,offsetBy: 1, limitedBy: word.endIndex) ?? word.startIndex
            let end = word.index(word.endIndex,offsetBy: -1, limitedBy: word.startIndex) ?? word.endIndex
            return checkPalindrome(word[start..<end])
        } else {
            return false
        }
    }
}
checkPalindrome("Dammit I'm Mad")

答案 2 :(得分:2)

如果

,只需添加更多条件
        func checkPalindrome(word: String) -> Bool {
        print(word)
    if (word == "" || word.characters.count == 1){
            return true

        }
    else {
            if word.characters.first == word.characters.last {
                return checkPalindrome(word.substringWithRange(word.startIndex.successor() ..< word.endIndex.predecessor()))
            } else {
                return false
            }
        }
    }

答案 3 :(得分:2)

func isPalindrome(myString:String) -> Bool {
    let reverseString = String(myString.characters.reversed())
    if(myString != "" && myString == reverseString) {
        return true
    } else {
        return false
    }
}

print(isPalindrome("madam"))

答案 4 :(得分:1)

我认为如果你像这样扩展String,那么它会让你的生活更轻松:

extension String {
    var length: Int { return characters.count }

    subscript(index: Int) -> Character {
        return self[startIndex.advancedBy(index)]
    }

    subscript(range: Range<Int>) -> String {
        return self[Range<Index>(start: startIndex.advancedBy(range.startIndex), end: startIndex.advancedBy(range.endIndex))]
    }
}

有了它,您可以将功能更改为:

func checkPalindrome(word: String) -> Bool {
    if word.length < 2 {
        return true
    } 

    if word.characters.first != word.characters.last {
        return false
    }

    return checkPalindrome(word[1..<word.length - 1])
}

快速测试:

print(checkPalindrome("aba")) // Prints "true"
print(checkPalindrome("abc")) // Prints "false"

答案 5 :(得分:1)

if word == String(word.reversed())
{
    return true
}
return false

答案 6 :(得分:0)

并没有真正想到这一点,但我想我想出了一个非常酷的扩展,并且认为我会分享。

extension String {
    var subString: (Int?) -> (Int?) -> String {
        return { (start) in
            { (end) in
                let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
                let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)

                return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
            }
        }
    }
}


let test = ["Eye", "Pop", "Noon", "Level", "Radar", "Kayak", "Rotator", "Redivider", "Detartrated", "Tattarrattat", "Aibohphobia", "Eve", "Bob", "Otto", "Anna", "Hannah", "Evil olive", "Mirror rim", "Stack cats", "Doom mood", "Rise to vote sir", "Step on no pets", "Never odd or even", "A nut for a jar of tuna", "No lemon, no melon", "Some men interpret nine memos", "Gateman sees name, garageman sees nametag"]

func checkPalindrome(word: String) -> Bool {
    if word.isEmpty { return true }
    else {
        if word.subString(nil)(1) == word.subString(-1)(nil) {
            return checkPalindrome(word.subString(1)(-1))
        } else {
            return false
        }
    }
}

for item in test.map({ $0.lowercaseString.stringByReplacingOccurrencesOfString(",", withString: "").stringByReplacingOccurrencesOfString(" ", withString: "") }) {
    if !checkPalindrome(item) {
        print(item)
    }
}

答案 7 :(得分:0)

我已经使用下面的扩展名来查找数字是否为回文。

@login_required
def user_profile(request, username):
    image = request.user.profile.img
    image = str(image)
    image = image.strip('users/%s' % username)
    return render(request, 'user_profile.html', {'username': request.user.username,
                                                 'image': image})

答案 8 :(得分:0)

extension String {

    func trimmingFirstAndLastCharacters() -> String {
        guard let startIndex = index(self.startIndex, offsetBy: 1, limitedBy: self.endIndex) else {
            return self
        }

        guard let endIndex = index(self.endIndex, offsetBy: -1, limitedBy: self.startIndex) else {
            return self
        }

        guard endIndex >= startIndex else {
            return self
        }

        return String(self[startIndex..<endIndex])
    }

    var isPalindrome: Bool {
        guard count > 1 else {
            return true
        }

        return first == last && trimmingFirstAndLastCharacters().isPalindrome
    }
}

我们首先声明一个函数,该函数从字符串中删除第一个和最后一个字符。

接下来,我们声明一个计算机属性,其中将包含检查字符串是否为回文符的实际递归代码。

如果字符串的大小小于或等于1,我们将立即返回true(由一个字符组成的字符串,如"a"或空字符串""被视为回文),否则我们检查是否字符串的第一个和最后一个字符是相同的,我们递归调用当前字符串上的isPalindrome,该字符串不包含第一个和最后一个字符。

答案 9 :(得分:0)

将字符串转换为数组。执行循环时,获取第一个索引并与最后一个索引进行比较。

func palindrome(string: String)-> Bool{
    let char = Array(string)
    for i in 0..<char.count / 2 {
        if char[i] != char[char.count - 1 - i] {
            return false
        }
    }
    return true
}

答案 10 :(得分:0)

这个解决方案不是递归的,但它是一个基于 O(n) 纯索引的解决方案,没有过滤任何东西,也没有创建新对象。非字母字符也会被忽略。

采用两个索引,从两侧向外走。

我承认扩展类型和属性名称是从Leo那里偷来的,我深表歉意。 ?

extension StringProtocol where Self: RangeReplaceableCollection {
    var isPalindrome : Bool {
        if isEmpty { return false }
        if index(after: startIndex) == endIndex { return true }
        var forward = startIndex
        var backward = endIndex
        while forward < backward {
            repeat { formIndex(before: &backward) } while !self[backward].isLetter
            if self[forward].lowercased() != self[backward].lowercased() { return false }
            repeat { formIndex(after: &forward) } while !self[forward].isLetter
        }
        return true
    }
}

答案 11 :(得分:-1)

func checkPalindrome(_ inputString: String) -> Bool {
    if inputString.count % 2 == 0 {
        return false
    } else if inputString.count == 1 {
        return true
    } else {
        var stringCount = inputString.count
        while stringCount != 1 {
            if inputString.first == inputString.last {
                stringCount -= 2
            } else {
                continue
            }
        }
        if stringCount == 1 {
            return true
        } else {
            return false
        }
    }
}
相关问题