我想你可以在有O(1)内存使用和同为O(n)速度方面得到较好的解决。通过处理链接列表。您不必创建链接列表的反转副本。但是这种方法破坏了列表。你将不得不将它缝合到位,但运行时间仍然是O(n)。
isPalindrome的快速版本的代码基本上找到链接列表的中间,然后从逻辑上将链接列表分成2个部分。它只反转了第一部分,并与另一部分进行比较。坏的部分是由于第一个链表上的块就地反转而破坏了链表。但是,您可以将列表重新拼接在一起,并且仍然处于O(n)时间。
要看的功能是isPalindromeFast。我开始了,但还没有完成完成。你可以在这里运行代码http://play.golang.org/p/3pb4hxdRIp。
这里是Go的完整代码。
package main
import "fmt"
type Node struct {
value string
next *Node
}
func (n *Node) Next() *Node {
return n.next
}
func (n *Node) Value() string {
return n.value
}
func (n *Node) Length() int {
length := 0
linkedList := n
for linkedList != nil {
length += 1
linkedList = linkedList.Next()
}
return length
}
func NewLinkedList(s string) *Node {
if len(s) == 0 {
return nil
}
headNode := &Node{string(s[0]), nil}
currentNode := headNode
for _, v := range s[1:] {
newNode := &Node{string(v), nil}
currentNode.next = newNode
currentNode = newNode
}
return headNode
}
func PrintLinkedList(linkedList *Node) {
for linkedList != nil {
fmt.Println(linkedList)
linkedList = linkedList.Next()
}
}
func ReverseList(linkedList *Node, endPoint int) *Node {
if endPoint == 1 {
return linkedList
}
first, next, lastNode := linkedList, linkedList, linkedList
lastNode = nil
for i := 0; i < endPoint; i++ {
next = first.Next()
first.next = lastNode
lastNode = first
first = next
}
return lastNode
}
// func StitchListsBackTogether(listA, listB, listC *Node, endOfListA int) *Node {
// listAFixed := ReverseList(listA, endOfListA)
// listStart := listAFixed
// for listAFixed.Next() != nil {
// listAFixed = listAFixed.Next()
// }
// listAFixed.next = listB
// return listStart
// }
func IsPalindromeFast(linkedList *Node) bool {
// Uses O(1) space and O(n) time
// However mutates and destroys list, so need to stitch list backtogether. Initial implementation StitchListsBackTogether
length := linkedList.Length()
endOfListA := length/2
endOfListB := length/2
if length%2 == 0 {
endOfListB += 1
} else {
endOfListB += 2
}
listA, listB := linkedList, linkedList
for i := 0; i < endOfListB-1; i++ {
listB = listB.Next()
}
listA = ReverseList(listA, endOfListA)
for listA != nil && listB != nil {
if listA.Value() != listB.Value() {
return false
}
listA = listA.Next()
listB = listB.Next()
}
return true
}
func IsPalindromeSlow(linkedList *Node) bool {
//Uses O(1) space and O(n^2) time
startPalidrome, endPalidrome := linkedList, linkedList
for endPalidrome.Next() != nil {
endPalidrome = endPalidrome.Next()
}
for startPalidrome != endPalidrome {
if startPalidrome.Value() != endPalidrome.Value() {
return false
}
if startPalidrome.Next() == endPalidrome {
return true
}
startPalidrome = startPalidrome.Next()
middlePalidrome := startPalidrome
for middlePalidrome.Next() != endPalidrome {
middlePalidrome = middlePalidrome.Next()
}
endPalidrome = middlePalidrome
}
return true
}
func main() {
fmt.Println(IsPalindromeSlow(NewLinkedList("ttoott")))
fmt.Println(IsPalindromeFast(NewLinkedList("ttoott")))
fmt.Println("")
fmt.Println(IsPalindromeSlow(NewLinkedList("ttott")))
fmt.Println(IsPalindromeFast(NewLinkedList("ttott")))
fmt.Println("")
fmt.Println(IsPalindromeSlow(NewLinkedList("hello")))
fmt.Println(IsPalindromeFast(NewLinkedList("hello")))
fmt.Println("")
fmt.Println(IsPalindromeSlow(NewLinkedList("ttto")))
fmt.Println(IsPalindromeFast(NewLinkedList("ttto")))
fmt.Println("")
fmt.Println(IsPalindromeSlow(NewLinkedList("tt")))
fmt.Println(IsPalindromeFast(NewLinkedList("tt")))
fmt.Println("")
fmt.Println(IsPalindromeSlow(NewLinkedList("t")))
fmt.Println(IsPalindromeFast(NewLinkedList("t")))
fmt.Println("")
fmt.Println(IsPalindromeSlow(NewLinkedList("tto3tt")))
fmt.Println(IsPalindromeFast(NewLinkedList("tto3tt")))
fmt.Println("")
}
不是一个解决方案,只是一个提示:你的功能是找出是否是真的。所以它应该返回一个'bool',而不是'int'。同样,称它为“palindromeOrNot”是不明确的。 “isPalindrome”会更有意义。 – Widor
Ok.Thanks.B你可以建议一些答案 – aj983