意图
使用单向链表实现判断一个字符串是否是回文字符串
思路
- 使用快、慢指针找出字符串中间那个数
- 找出前半部分字符串
- 遍历前半部分,和整个字符串挨个比较字符,如果都相等,则是回文字符串,反之不是
开发环境
- swift4.2
- Xcode11.3
示例代码
Node类
class Node<T>: NSObject, NSCopying {
var next: Node?
var data: T?
override init() { }
init(data: T?) {
self.data = data
}
// 实现NSCopying协议方法
func copy(with zone: NSZone? = nil) -> Any {
var node: Node<T>? = self
var copy: Node<T>?
while node != nil {
let tmp: Node<T>? = Node()
tmp?.data = node?.data
if node?.next != nil {
tmp?.next = Node(data: node?.next?.data)
}
setNext(©, next: tmp)
node = node?.next?.next
}
return copy as Any
}
// 设置子节点
private func setNext(_ source: inout Node<T>?, next: Node<T>?) {
if source == nil {
source = next
return
}
if source?.next == nil {
source?.next = next
return
}
var sourceNext = source?.next
setNext(&sourceNext, next: next)
}
// 格式化打印对象
override var description: String {
var result = ""
var node: Node<T>? = self
while node != nil {
if let data = node?.data {
result += "\(data),"
node = node?.next
}
}
if result.count > 0 {
// 删除最后一个逗号
result.removeLast()
}
return result
}
}
判断是否是回文字符串
func isPalindrome(_ str: Node<String>) -> Bool {
// TIPS: 这里需要拷贝,否则在第二步操作的时候,会对源节点做修改
var fast = str.copy() as? Node<String>
var slow = str.copy() as? Node<String>
// 1.找出回文中间那个数
// 循环结束,fast指针指向最后一个元素,slow指针指向中间那个元素
while fast?.next != nil && fast?.next?.next != nil {
fast = fast?.next?.next
slow = slow?.next
}
var current = slow?.next
// 2.找出前半部分
var pre: Node<String>? // 回文前半部分
while current != nil {
let next = current?.next
current?.next = pre
pre = current
current = next
}
// 遍历前半部分,和整个字符串挨个比较字符,如果都相等,则是回文字符串,反之不是
var n1: Node<String>? = pre
var n2: Node<String>? = str
while pre != nil {
if !(pre?.data == n2?.data) {
return false
}
n1 = n1?.next
n2 = n2?.next
}
return true
}
调用
/// 生成单链表
// 奇数回文
private func oddPalindrome() -> Node<String> {
let node = Node(data: "1")
node.next = Node(data: "2")
node.next?.next = Node(data: "3")
node.next?.next?.next = Node(data: "2")
node.next?.next?.next?.next = Node(data: "1")
return node
}
// 偶数回文
private func oddPalindrome() -> Node<String> {
let node = Node(data: "1")
node.next = Node(data: "2")
node.next?.next = Node(data: "3")
node.next?.next?.next = Node(data: "3")
node.next?.next?.next?.next = Node(data: "2")
node.next?.next?.next?.next?.next = Node(data: "1")
return node
}
// 不是回文
private func errorPalindrome() -> Node<String> {
let node = Node(data: "1")
node.next = Node(data: "2")
node.next?.next = Node(data: "3")
node.next?.next?.next = Node(data: "2")
return node
}
override func viewDidLoad() {
super.viewDidLoad()
let oddNode = oddPalindrome()
let evenNode = evenPalindrome()
let errorNode = errorPalindrome()
println("\(oddNode) \(isPalindrome(oddNode) ? "是" : "不是")回文字符串")
println("\(evenNode) \(isPalindrome(evenNode) ? "是" : "不是")回文字符串")
println("\(errorNode) \(isPalindrome(errorNode) ? "是" : "不是")回文字符串")
}
思考
使用双向链表如何实现?