题目描述:给定一个链表的 头节点 head
,请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
例如:[1,2,3,3,2,1] 是回文
解法一:栈实现完全翻转
时间复杂度O( n ),空间复杂度O( n )
将链表节点顺序放入栈中 ,依次出栈与链表一一比较。原理:栈先进后出实现了链表的逆序
code:
public void isPalindrome(ListNode head){
if(head == null || head.next == null){
return true;
}
Stack<ListNode> stack = new Stack<>();
ListNode p = head;
while(p != null){
stack.push(p);
p = p.next;
}
p = head;
while(!stack.isEmpty()){
if(p.val != stack.pop().val){
return false;
}
p = p.next;
}
return true;
}
解法二:快慢指针结合栈
时间复杂度O( n ),空间复杂度O( n / 2 ) ,节省了一半空间
利用快慢指针找到中点,将中点后面的加入栈中逆序
code:
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null){
return true;
}
ListNode S = head;
ListNode F = head.next;
while(F.next != null && F.next.next != null){
S = S.next;
F = F.next.next;
}
Stack<ListNode> stack = new Stack<>();
while(S != null){
stack.push(S);
S = S.next;
}
S = head;
while(!stack.isEmpty()){
if(stack.pop().val != S.val){
return false;
}
S = S.next;
}
return true;
}
解法三:快慢指针,中点之后进行逆序
时间复杂度O( n ),空间复杂度O( 1 ) 。在原链表上进行修改操作,没有借助其他的数据结构,大大的节省了空间
找到中点后,对中点之后节点反转,再两头同时进行遍历比较,之后再对逆序部分进行恢复
code:
public boolean isPalindrome(ListNode head) {
boolean flag = true;
if(head == null || head.next == null){
return true;
}
ListNode S = head;
ListNode F = head.next;
while(F.next != null && F.next.next != null){
S = S.next;
F = F.next.next;
}
//逆序
ListNode next = null;
ListNode pre = null;
while(S != null){
next = S.next;
S.next = pre;
pre = S;
S = next;
}
//记录中点
ListNode mid = S;
//两头遍历比较
S = head;
//记录pre节点
ListNode n = pre;
while(S != null){
if(pre.val != S.val){
flag = false;
break;
}
pre = pre.next;
S = S.next;
}
//pre 已经为 null
//恢复逆序部分
while(n != null){
next = n.next;
n.next = pre;
pre = n;
n = next;
}
return flag;
}