经典算法:回文链表
题目: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 leetcodeimport ("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, headfor 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, headfor curr != nil {prev, curr, curr.Next = curr, curr.Next, prev}return prev
}
单元测试
package leetcodeimport ("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 argswant 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)}
}