根据回文对称的特点,不难想到将链表分成前后两部分,然后将其中一部分反转的方法。
可以使用快慢指针的方式找到链表的中点,其中快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针指向的位置即为链表的中点。
然后将链表的后半部分反转,比较前半部分和反转后的后半部分,从而判断链表是否为回文链表。
public boolean isPalindrome(ListNode head) {// 初始化快慢指针,均指向链表头部ListNode fast = head;ListNode slow = head;// 使用快慢指针找到链表中点while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}// 反转后半部分链表ListNode root = null;while (slow != null) {ListNode tmp = slow.next;slow.next = root;root = slow;slow = tmp;}// 比较前半部分和反转后的后半部分链表fast = head;while (root != null) {// 如果节点值不相等,说明链表不是回文链表,返回 falseif (fast.val != root.val) {return false;}// 移动指针fast = fast.next;root = root.next;}// 遍历完成,说明链表是回文链表,返回 truereturn true;}
这段代码中在处理奇数长度的链表时选择保留中间节点,当然你也可以选择舍弃比较中间节点。如下:
public boolean isPalindrome(ListNode head){// 如果链表为空或只有一个节点,认为是回文链表if (head == null || head.next == null){return true;}// 使用快慢指针找到链表中点ListNode slow = head;ListNode fast = head.next;// 当链表长度是奇数时,循环结束时slow位于中间节点的前一个节点while (fast.next != null && fast.next.next != null){fast = fast.next.next;slow = slow.next;}// 获取后半部分链表的头节点ListNode secondHalf = slow.next;if (fast.next != null){// 当链表长度是奇数时,就要多移动一步secondHalf = slow.next.next;}// 切断前半部分链表与后半部分链表的连接slow.next = null;// 比较前半部分和反转后的后半部分链表是否相等return equals(secondHalf, reverseList(head));}// 比较两个链表是否相等private boolean equals(ListNode head1, ListNode head2){while (head1 != null && head2 != null){if (head1.val != head2.val){return false;}head1 = head1.next;head2 = head2.next;}return head1 == null && head2 == null;}// 反转链表private ListNode reverseList(ListNode head) {ListNode prev = null;ListNode cur = head;while (cur != null) {ListNode next = cur.next;cur.next = prev;prev = cur;cur = next;}return prev;}