判断一个链表是否为回文结构

给定一个链表的头节点head,请判断该链表是不是回文结构。
例如:
1->2->1,返回true。
1->2->2->1,返回true。
15->6->15,返回true。
1->2->3,返回false。

思路 & 代码

1
2
3
4
5
6
7
8
9
//链表结构
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}

空间复杂度O(n/2)

使用2个指针,一个快一个慢,快的一次走2步,慢的一次走一步,直到空为止
此时慢指针停在中间位置,然后将慢指针后面的内容入栈
因为栈是逆序的,所以相当于将后半部分的链表逆序
然后从栈顶与链表头开始比较是否相同
当元素个数为奇数时,如1,2,3,2,1,入栈的值为3,2,1
当元素个数为偶数时,如1,2,3,4,2,1,入栈的值为4,2,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
public static boolean isPalindrome1(Node head) {
if(head == null || head.next == null){
//链表为空或者只有一个元素
return true;
}
//慢指针
Node ns = head;
//快指针
Node nq = head;
//这里判断的条件不是nq.next.next
//因为可能nq到了末尾,而nq.next为空,nq.next.next是不存在的
//也可能是nq为被赋值为空
while(nq != null && nq.next != null){
//快指针一次走2步,慢指针一次走一步
ns = ns.next;
nq = nq.next.next;
}
Stack<Node> stack = new Stack<Node>();
//慢指针的后半段入栈
while(ns != null){
stack.push(ns);
ns = ns.next;
}
//栈中内容与链表头开始比较
while(!stack.empty()){
if(head.value != stack.pop().value){
//元素不符合
return false;
}
head = head.next;
}
return true;
}

空间复杂度O(1)

该方法改变了链接的结构,之后要进行还原
这个方法与前一种部分类似,也是在快慢指针一起走直到为空。
之后就有所区别了,即将慢指针后半部分的值全部反向指

  • 原链表为1,2,3,2,1,修改后为1->2->3<-2<-1
  • 原链表为1,2,3,4,2,1,修改后为1->2->3->4<-2<-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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//只用空间复杂度O(1)
public static boolean isPalindrome2(Node head) {
boolean res = true;
if(head == null || head.next == null){
//链表为空或者只有一个元素
return true;
}
//慢指针
Node ns = head;
//快指针
Node nq = head;
while(nq != null && nq.next != null){
ns = ns.next;
nq = nq.next.next;
}
//将ns后面的链表反转
Node prior = ns;
Node cur = ns.next;
//两个节点单独判断
if(cur == null){
//说明此链表中只有2个元素,直接返回不需要修复
return head.value == ns.value ? true: false;
}
//只有两个节点的时候,无nextNode
Node nextNode = cur.next;
//将中间的节点的后继设为空
ns.next = null;
while(cur != null) {
//反向指
cur.next = prior;
prior = cur;
cur = nextNode;
//判空,因为cur为空,nextNode不存在
if(cur == null){
break;
}
nextNode = nextNode.next;
}
//结束后prior就是头结点
//head和prior不能破坏因为还要修复链表
ns = head;
cur = prior;
//判断是否是回文
while(ns != null && cur != null){
if(ns.value != cur.value){
res = false;
}
ns = ns.next;
cur = cur.next;
}
//修复链表
cur = prior.next;
//nextNode可能为空,当只有3个元素的时候,所以下面重置nextNode会判断
nextNode = cur.next;
prior.next = null;
while(cur != null){
cur.next = prior;
prior = cur;
cur = nextNode;
//判空,因为cur为空,nextNode不存在
if(cur == null){
break;
}
nextNode = nextNode.next;
}
return res;
}