力扣热题100刷题day61|234.回文链表(两种方法)
一、回文链表
234.回文链表
两种解法
解法1:时间复杂度O(n) 空间复杂度O(n)
遍历链表,计算链表长度,创建同样长度大小的数组,用数组存储链表中所有元素,之后双指针遍历链表,一个从头开始,一个从尾开始,比较元素是否相等;
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode curr = head;
int len = 0;
if(head.next == null){
return true;
}
while(curr != null){
len++;
curr = curr.next;
}
//重置curr
curr = head;
int[] nums = new int[len];
for(int i = 0;i < nums.length;i++){
if(curr != null){
nums[i] = curr.val;
curr = curr.next;
}
else{
break;
}
}
for(int i = 0,j = nums.length - 1;i < j;i++,j--){
if(nums[i] != nums[j]) return false;
}
return true;
}
}
注意⚠️:求完链表长度后,记得重置curr;
解法2:时间复杂度O(n) 空间复杂度O(1)
快慢指针法(⭐️)
定义两个指针,快指针fast,慢指针slow,初始指向头结点,只要fast != null && fast.next != null,那么慢指针每次移动一个结点,快指针每次移动两个结点;直到fast不满足条件,此时,慢指针指向中点(链表个数为奇数),或者中点偏右的位置(链表个数为偶数);
之后,反转后半部分链表,然后比较前后两部分的数值,相等,则为回文链表,否则不是;
使用快慢指针法找到链表的中点的原理:
快指针的速度是慢指针的 2 倍,所以当快指针走完全程时,慢指针刚好走了一半。
慢指针走过的路程为 x,那么快指针就是2x,2x = len,则x = 1/2 len;
class Solution {
public boolean isPalindrome(ListNode head) {
//快慢指针
ListNode slow = new ListNode();
ListNode fast = new ListNode();
if(head == null || head.next == null){
return true;
}
slow = head;
fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
//若链表为奇数个 此时slow指向中间点
//若链表为偶数个 此时slow指向中间偏右的结点
//反转后半部分链表
ListNode pre = null;
ListNode curr = slow;
while(curr != null){
ListNode temp = curr.next;
curr.next = pre;
pre = curr;
curr = temp;
}
//此时pre指向反转后链表的头部
//比较前后两部分链表
ListNode pA = head;
ListNode pB = pre;
while(pB != null){
if(pA.val != pB.val){
return false;
}
pA = pA.next;
pB = pB.next;
}
return true;
}
}
注意⚠️:在比较前后两部分链表时,while中的判断条件只能是pB != null;
如果是pA != null,那么当链表个数为偶数时:1 2 3 4;
slow最后指向3,后半部分反转后,整体链表结构为:
前:1 --> 2 -->3 --> null
后:4 ---> 3 --> null
pA遍历的是前半部分的链表,pB遍历后半部分,当pB指向null时,pA指向3,不为空,进入循环,pB.val就会报错:空指针异常;