题目:234. 回文链表
给你一个单链表的头节点 head
,请你判断该链表是否为 回文链表。如果是,返回 true
;否则,返回 false
。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
提示:
- 链表中节点数目在范围[1, 10 5 10^5 105] 内
0 <= Node.val <= 9
进阶: 你能否用 $ O(n) $ 时间复杂度和 $ O(1) $ 空间复杂度解决此题?
解题思路
通过快慢指针找到中点,反转后半部分链表且进行比较。
实现代码
package leetcode
import (
"github.com/superproj/go-leetcode/structure"
)
// ListNode define
type ListNode = structure.ListNode
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func isPalindrome(head *ListNode) bool {
if head == nil {
return true
}
// 找出中点,快指针到了链表结尾,慢指针也就到了链表中点
mid := findMid(head)
// 翻转后半部分链表
rev := reverse(mid)
// 比对前后链表
for rev != nil && head != nil {
if head.Val != rev.Val {
return false
}
rev, head = rev.Next, head.Next
}
return true
}
func findMid(head *ListNode) *ListNode {
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow, fast = slow.Next, fast.Next.Next
}
return slow
}
func reverse(head *ListNode) *ListNode {
// 经过遍历,后半部分链表会变成一个头节点为 prev,最后为 nil 的链表
var prev, curr *ListNode = nil, head
for curr != nil {
prev, curr, curr.Next = curr, curr.Next, prev
}
return prev
}
单元测试
package leetcode
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/superproj/go-leetcode/structure"
)
func Test_isPalindrome(t *testing.T) {
assert := assert.New(t)
type args struct {
first []int
}
tests := []struct {
args args
want bool
}{
{
args: args{[]int{1, 1, 2, 2, 3, 4, 4, 4}},
want: false,
},
{
args: args{[]int{1, 1, 1, 1, 1, 1}},
want: true,
},
{
args: args{[]int{1, 2, 2, 1, 3}},
want: false,
},
{
args: args{[]int{1}},
want: true,
},
{
args: args{[]int{}},
want: true,
},
{
args: args{[]int{1, 2, 2, 2, 2, 1}},
want: true,
},
{
args: args{[]int{1, 2, 2, 3, 3, 3, 3, 2, 2, 1}},
want: true,
},
{
args: args{[]int{1, 2}},
want: false,
},
{
args: args{[]int{1, 0, 1}},
want: true,
},
{
args: args{[]int{1, 1, 2, 1}},
want: false,
},
}
for _, tt := range tests {
first := structure.Ints2List(tt.args.first)
actual := isPalindrome(first)
assert.Equal(tt.want, actual)
}
}