【题目】
给定一个链表的头节点head,请判断该链表是否为回文结构。
例如: 1->2->1,返回true;1->2->2->1,返回true;15->6->15,返回true; 1->2->3,返回false。
【思路】
【第一种解法】(额外的空间复杂度是O(n))
1.准备一个栈,遍历链表中的数据存到栈中;
2.再遍历一次链表数据,同时把栈中数据依次弹出(相当于把链表数据反序),逐个比较。
【代码实现】
//1.构造链表结构(链表是许多结点构成,结点是数值和指针(指向的是下一个结点)构成)
public static class Node{
int value;
Node next;
public Node(int data) {
this.value=data;
}
}
//2.核心函数
public static boolean isHuiWen(Node head){
//2.1链表中的数据压入栈
Stack<Node> stack=new Stack<>();
Node cur=head;
while(cur!=null){
stack.push(cur);
cur=cur.next;
}
//2.2 链表中的数据和栈中数据比较
while(head!=null){
if(head.value!=stack.pop().value){
return false;
}
head=head.next;
}
return true;
}
【第二种解法】(额外的空间复杂度是O(n),但是节省了一半的空间)
1.设定一个快指针cur,每次走两步;
2.设定一个慢指针head,每次走一步;
3.当快指针不能再走的时候,就停止,此时慢指针所在的位置就是中间位置(奇数个结点恰好中间位置,偶数个结点则走到靠后边的中间位置);
4.把慢指针及之后的数据存入到栈中
5.慢指针前面的和栈依次弹出的数据逐个进行比较;
【代码实现】
public static boolean isPalindrome2(Node head) {
//1.没有头结点或者只有头结点返回true
if (head == null || head.next == null) {
return true;
}
//2.设定慢结点right(为了保证偶数个的时候在后边的中间位置,他从第一个结点开始移动,每次一步);设定快结点cur(从头结点开始走,每次两步)
Node right = head.next;
Node cur = head;
while (cur.next != null && cur.next.next != null) {
right = right.next;
cur = cur.next.next;
}
//3.把中间位置及其以后的数据放到栈中
Stack<Node> stack = new Stack<Node>();
while (right != null) {
stack.push(right);
right = right.next;
}
//4.不断弹出栈中元素和前面的比较
while (!stack.isEmpty()) {
if (head.value != stack.pop().value) {
return false;
}
head = head.next;
}
return true;
}
【第三种解法】
1.找到中间位置;
2.中间位置及其以后结点改变指针指向,让后一个结点指向前一个结点;
3.左半部分和右半部分比较;
4.右半部分调整回原来的指向;
public static boolean isHuiWen3(Node head) {
if (head==null||head.next==null) {
return true;
}
Node n1=head;
Node n2=head;
while(n2.next!=null&&n2.next.next!=null) {
n1=n1.next;
n2=n2.next.next;
}
//1.改变右part指针方向
n2=n1.next;//n1移动到中间或者中间靠左位置 //n2是链表右半部分第一个结点
n1.next=null;//n1是链表左半部分最后一个结点,让他指向空(左半部分和右半部分断开关联)
Node n3=null;//辅助结点
//(翻转n2及其以后的节点)1.找到下一个结点 2.找到下一个位置n1 3.把后边的节点移动到他前边的位置
while(n2!=null) {
n3=n2.next;//找到下一个结点
n2.next=n1;//找到下一个结点的位置(改变指针方向,他就相当于是改变之后的前边位置)
n1=n2;//(把当前节点移动到它的前一位)
n2=n3;//(把当前节点的后一个结点移动到当前节点的位置)
}
//2.比较方法
n3=n1;//n3保存右part最后一个结点
n2=head;//n2是左part第一个结点
boolean res=true;
while(n1!=null&&n2!=null) {
if(n1.value!=n2.value) {
res=false;
break;
}
n1=n1.next;
n2=n2.next;
}
//3.调整回右part原来的指针指向
n1=n3.next;//n3保存右part第一个元素,n1是下一个结点
n3.next=null;//
while(n1!=null) {
n2=n1.next;//找到n1的下一个结点
n1.next=n3;//找到n1的下一个位置(就是之后前边位置)
n3=n1;//后边的都往前移一个位置
n1=n2;
}
return res;
}