给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false

可以借用一下集合,集合可以通过索引从两头向中间一一遍历元素,遍历的同时就可以一一比较元素值是否相同:
public boolean isPalindrome(ListNode head) {List<Integer> valList = new ArrayList<>();// 遍历链表,将节点放入 ListListNode cur = head;while (cur != null) {valList.add(cur.val);cur = cur.next;}// 双指针从 List 两头同时遍历并比较是否相同int left = 0;int right = valList.size() - 1;while (true) {// 走到同一个节点,表示链表的节点数量是奇数if (left == right) {return true;}// 左指针走到了右指针后侧,表示链表的节点数量是偶数if (left > right) {return true;}// 只要有某个值不同,则表示不是回文链表if (!valList.get(left).equals(valList.get(right))) {return false;}left++;right--;}}
通过集合的思路,如果直接在链表中能够也找到两个指针,那么是否也可以达到相同的效果呢?
假设链表的节点数量是偶数:
假设链表的节点数量是奇数:
而 876. 链表的中间结点 情况和上述类似:
1)链表的节点数量是奇数时,和上述节点数量是奇数的情况一致
2)链表的节点数量是偶数时,和上述节点数量是偶数的情况稍稍有点不同,上述情况找的是链表前半部分的最后一个节点,而在链表的中间结点中是链表后半部分的第一个节点
/*** 找到链表中点* 节点数量是奇数时,则刚好是中间节点* 节点数量是偶数时,则刚好是后半部分第一个节点* @param head* @return*/public ListNode middleNode(ListNode head) {// 快慢指针都指向头结点ListNode fast = head;ListNode slow = head;// 快指针或者快指针的下一个节点是 null 时while(fast != null && fast.next != null) {// 慢指针走一步,快指针走两步slow = slow.next;fast = fast.next.next;}// 慢指针指向中点return slow;}
稍稍改动一下上述算法:
/*** 找到链表中点* 节点数量是奇数时,则刚好是中间节点* 节点数量是偶数时,则刚好是前半部分最后一个节点* @param head* @return*/public ListNode middleNode(ListNode head) {// 快慢指针都指向头结点ListNode fast = head;ListNode slow = head;// 快指针的下一个节点或者下下一个节点是 null 时while (fast.next != null && fast.next.next != null) {// 慢指针走一步,快指针走两步slow = slow.next;fast = fast.next.next;}return slow;}
那么直接利用双指针算法如下:
public boolean isPalindrome(ListNode head) {if (head == null) {return true;}// 找到前半部分链表的尾节点并反转后半部分链表ListNode firstHalfEnd = endOfFirstHalf(head);ListNode secondHalfStart = reverseList(firstHalfEnd.next);// 判断是否回文ListNode slow = head;ListNode fast = secondHalfStart;boolean isPalindrome = true;while (isPalindrome && fast != null) {if (slow.val != fast.val) {isPalindrome = false;}slow = slow.next;fast = fast.next;}// 还原链表并返回结果firstHalfEnd.next = reverseList(secondHalfStart);return isPalindrome;}/*** 找到链表前半部分最后一个节点** @param head* @return*/public ListNode endOfFirstHalf(ListNode head) {ListNode fast = head;ListNode slow = head;while (fast.next != null && fast.next.next != null) {fast = fast.next.next;slow = slow.next;}return slow;}/*** 反转链表** @param head* @return*/public ListNode reverseList(ListNode head) {ListNode prev = null;ListNode curr = head;while (curr != null) {ListNode nextTemp = curr.next;curr.next = prev;prev = curr;curr = nextTemp;}return prev;}
