一、回文链表
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;}//重置currcurr = 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就会报错:空指针异常;