1、题目描述
2、解法
2.1、使用额外的链表来存储,比较两个链表
比较简单,但是效率也比较慢。时间复杂度O(n),空间复杂度O(n);
2.2、模拟树的后序遍历,利用递归
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//定义一个指针记录头结点
ListNode left = null;
public boolean isPalindrome(ListNode head) {
if(head==null||head.next==null){
return true;
}
//定义一个指针记录头结点
left = head;
//反序遍历head
return traverse(head);
}
private boolean traverse(ListNode right){
if(right==null) return true;
//递归实现逆序后序遍历
boolean res = traverse(right.next);
//比较,判断回文
res = res && (right.val==left.val);
//移动下一个结点进行比较
left = left.next;
return res;
}
}
时间复杂度O(n),空间复杂度O(n);
2.3、解法三:链表部分反转,双判断回文
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if(head==null){
return true;
}
//1、查找中心的结点,如果是奇数,结点仅一个,偶数则两个
ListNode slow=head,fast=head;//使用快慢指针,每次slow走一步、fast走两步,n次就是slow——n,fast——2n
while(fast!=null && fast.next !=null ){
//一直走
slow = slow.next;
fast = fast.next.next;
}
if(fast != null){
//奇数
slow = slow.next;
}
//反转slow之后的链表
ListNode last = reverse(slow);
//比较两端链表
while(last!=null){
//从反转的链表比较
if(head.val!=last.val){
return false;
}
head = head.next;
last = last.next;
}
return true;
}
public ListNode reverse(ListNode head){
if(head==null||head.next==null) return head;
ListNode last = reverse(head.next);//逆序下一部分
//同时链接当前的结点
head.next.next = head;
head.next = null;//释放
return last;
}
}
复杂度同上。
2.4、解法四、将反转链表的方法使用为迭代(破坏链表原有结构)
public ListNode reverse(ListNode head){
ListNode pre = null,cur=head,next=head;
while(cur!=null){
next = cur.next;
cur.next = pre;//反转
//进行下一个结点的反转
pre = cur;
cur = next;
}
return pre;
}
时间复杂度O(n),空间复杂度O(1)。
我们破坏了输入链表的结构,要修复这个问题,我们可以通过在返回判断结果之前再选择将链表逆序,两次逆序,结构不变。所以我们需要记录哪里是逆序的结点起始位置和终止位置,然后调用类似如下的方法:
我还没测试过的代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
//为了恢复链表结构,记录的指针-------------------------------------------
ListNode start=null,end=null;
public boolean isPalindrome(ListNode head) {
if(head==null){
return true;
}
//1、查找中心的结点,如果是奇数,结点仅一个,偶数则两个
ListNode slow=head,fast=head;//使用快慢指针,每次slow走一步、fast走两步,n次就是slow——n,fast——2n
while(fast!=null && fast.next !=null ){
//一直走
start = slow;//start一直位于slow的上一个结点------------
slow = slow.next;
fast = fast.next.next;
}
if(fast != null){
//奇数
start = slow;//start一直位于slow的上一个结点-------------
slow = slow.next;
}
//反转slow之后的链表
ListNode last = reverse(slow);
end = last;//记录逆序头结点-------------
//比较两端链表
while(last!=null){
//从反转的链表比较
if(head.val!=last.val){
return false;
}
head = head.next;
last = last.next;
}
//恢复结构-----------
start.next = reverse(end);;---------
//试着打印一手:
// while(start!=null){
// System.out.println(start.val);
// start = start.next;
// }
return true;
}
public ListNode reverse(ListNode head){
ListNode pre = null,cur=head,next=head;
while(cur!=null){
next = cur.next;
cur.next = pre;//反转
//进行下一个结点的反转
pre = cur;
cur = next;
}
return pre;
}
}