Featured image of post 234.回文链表

234.回文链表

问题描述

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false

示例 1:

输入:head = [1,2,2,1]

输出:true

示例 2:

输入:head = [1,2]

输出:false

提示:

  • 链表中节点数目在范围 [1, 105] 内
  • 0 <= Node.val <= 9

进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解法一:查找中间节点 + 翻转链表

我们可以将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,但是使用该函数的人通常不希望链表结构被更改。

该方法虽然可以将空间复杂度降到 O(1),但是在并发环境下,该方法也有缺点。在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func isPalindrome(head *ListNode) bool {
    // 处理空链表情况
    if head == nil {
        return true
    }
    midNode := middleNode(head)
    // 开始时如果不处理 head == nil 的情况,访问 midNode.Next 会导致程序 panic,因为 midNode 此时为 nil
    b := reverseList(midNode.Next)
    midNode.Next = nil
    a := head
    copyB := b
    res := true
    for a != nil && b != nil {
        if a.Val != b.Val {
            res = false
            break
        }
        a = a.Next
        b = b.Next
    }
    // 开始还原
    midNode.Next = reverseList(copyB)
    // 验证是否还原
    for head != nil {
        fmt.Printf("%d ", head.Val)
        head = head.Next
    }
    return res
}

func middleNode(head *ListNode) *ListNode {
    if head == nil {
        return nil
    }
    slow, fast := head, head
    for fast.Next != nil && fast.Next.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
    }
    return slow
}

func reverseList(head *ListNode) *ListNode {
    var prev *ListNode
    for head != nil {
        next := head.Next
        head.Next = prev
        prev = head
        head = next
    }
    return prev
}

解法二:递归

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

func isPalindrome(head *ListNode) bool {
    frontNode := head
    var check func(head *ListNode) bool
    // check(node) 检查以 node 为头节点的链表是否是回文链表
    check = func(head *ListNode) bool {
        if head == nil {
            return true
        }
        if !check(head.Next) {
            return false
        }
        if head.Val != frontNode.Val {
            return false
        }
        frontNode = frontNode.Next
        return true
    }
    return check(head)
}
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计