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

时间:2021-09-27 15:46:21

I like many of the features in Swift, but using manipulating strings are still a big pain in the ass.

我喜欢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
        }
    }
}

This code fails miserably whenever the string's length is an odd number. Of course I could make it so the first line of the block would be if word.characters.count < 2, but is there a way in Swift to get substrings and check easily?

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

Update I like many of the suggestions, but I guess the original question could be misleading a little, since it's a question about String more than getting the right results for the function.

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

For instance, in Python, checkPalindrome(word[1:-1]) would work fine for the recursive definition, whereas Swift code is much less graceful since it needs other bells and whistles.

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

7 个解决方案

#1


3  

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

You can also break your string into an array of characters and iterate through them until its half comparing one by one with its counterpart:

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

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
}

#2


2  

Sometimes having a front end for a recursion can simplify life. I sometimes do this when the arguments which are most convenient to use are not what I want in the user interface.

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

Would the following meet your needs?

以下是否满足您的需求?

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)
}

#3


1  

just add on more condition in if

只需在if中添加更多条件

        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
            }
        }
    }

#4


1  

I think if you make an extension to String like this one then it will make your life easier:

我想如果你像这样扩展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))]
    }
}

With it in place, you can change your function to this:

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

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])
}

Quick test:

快速测试:

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

#5


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
        }
    }
}

#6


0  

Wasn't really thinking of this, but I think I came up with a pretty cool extension, and thought I'd share.

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

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  

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

#1


3  

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

You can also break your string into an array of characters and iterate through them until its half comparing one by one with its counterpart:

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

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
}

#2


2  

Sometimes having a front end for a recursion can simplify life. I sometimes do this when the arguments which are most convenient to use are not what I want in the user interface.

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

Would the following meet your needs?

以下是否满足您的需求?

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)
}

#3


1  

just add on more condition in if

只需在if中添加更多条件

        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
            }
        }
    }

#4


1  

I think if you make an extension to String like this one then it will make your life easier:

我想如果你像这样扩展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))]
    }
}

With it in place, you can change your function to this:

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

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])
}

Quick test:

快速测试:

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

#5


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
        }
    }
}

#6


0  

Wasn't really thinking of this, but I think I came up with a pretty cool extension, and thought I'd share.

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

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  

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