链表逆序+判断链表是否回文
单链表逆序详解
1.具有链表头的单链表
假设需要逆序的单链表为:
![单链表逆序详解 单链表逆序详解](http://s3.sinaimg.cn/middle/705eb43at99cab5e9a672&690)
则逆序以后的链表为:
![单链表逆序详解 单链表逆序详解](http://s9.sinaimg.cn/middle/705eb43at99cabd5c4ab8&690)
过程:
(1)取p1指向header->next (p1=stu->next);p2保留p1->next(p2=p1->next);将p1->next置为NULL,因为单链表逆序以后,当前的p1节点为尾节点 p1->next=NULL;
(2)取p3保留p2->next (p3=p2->next);将p2插入p1之前(p2->next = p1);p1指向p2指向的节点(p1=p2);p2指向p3指向的节点(p2=p3);
![单链表逆序详解 单链表逆序详解](http://s6.sinaimg.cn/middle/705eb43at99cae05996f5&690)
循环一次修改以后的单链表如下:
(3)重复步骤(2)
循环一次修改以后的单链表如下:
(4)将header->next指向p1,完成整个单链表的逆序
2.链表回文
则逆序以后的链表为:
过程:
(1)取p1指向header->next (p1=stu->next);p2保留p1->next(p2=p1->next);将p1->next置为NULL,因为单链表逆序以后,当前的p1节点为尾节点 p1->next=NULL;
(2)取p3保留p2->next (p3=p2->next);将p2插入p1之前(p2->next = p1);p1指向p2指向的节点(p1=p2);p2指向p3指向的节点(p2=p3);
循环一次修改以后的单链表如下:
(3)重复步骤(2)
循环一次修改以后的单链表如下:
(4)将header->next指向p1,完成整个单链表的逆序
typedef struct student{ int number; char name[20]; int score; struct student *next; }student; student *reverse(student *stu){ student *p1,*p2,*p3; if(stu == NULL ||stu->next == NULL) return stu; p1=stu->next; //p1指向链表头节点的下一个节点 p2=p1->next; p1->next=NULL; while(p2){ p3=p2->next; p2->next = p1; p1=p2; p2=p3; } stu->next=p1; return stu; }
判断一个单向链表是否是回文链表,要求O(n)的时间复杂度和O(1)的空间复杂度。算法有以下几种:
- 遍历整个链表,将链表每个节点的值记录在数组中,再判断数组是不是一个回文数组,时间复杂度为O(n),但空间复杂度也为O(n),不满足空间复杂度要求。
- 利用栈先进后出的性质,将链表前半段压入栈中,再逐个弹出与链表后半段比较。时间复杂度O(n),但仍然需要n/2的栈空间,空间复杂度为O(n)。
- 反转链表法,将链表后半段原地翻转,再将前半段、后半段依次比较,判断是否相等,时间复杂度O(n),空间复杂度为O(1)满足题目要求。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public boolean chkPalindrome(ListNode A) { Stack<Integer> stack = new Stack<Integer>(); if (A == null || A.next == null) return true; ListNode quick = A; ListNode slow = A; boolean flag = false; while (quick != null) { stack.add(slow.val); slow = slow.next; quick = quick.next; if (quick != null) { quick = quick.next; } else { flag = true; } } if (flag == true) stack.pop(); while (!stack.isEmpty() && slow != null) { int va = stack.pop(); if (va == slow.val) slow = slow.next; else return false; } if (slow == null && stack.isEmpty()) return true; else return false; }
使用快慢指针和原地翻转的代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public boolean chkPalindrome(ListNode A) { if (A == null) return false; if (A.next == null) return true; ListNode quick = A; ListNode slow = A; while (quick != null && quick.next != null) { quick = quick.next.next; slow = slow.next; } ListNode p = slow.next; ListNode p1 = p.next; while (p != null) { p.next = slow; slow = p; p = p1; if (p1 != null) { p1 = p1.next; } } while (A != slow) { if (A.val != slow.val) { return false; } if(A.next==slow){ return true; } A = A.next; slow = slow.next; } return true; }
不忘初心,方得始终