【算法题】判断回文链表

359 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

题目链接:234. 回文链表 / 剑指 Offer II 027. 回文链表

题目描述

给你一个单链表的头节点 head,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false

Untitled.png

示例一:输入1→2→2→1,输出true
示例二:输入1→2,输出false

前言

我们一般判断回文都是在数组或者字符串中通过左右指针向中间靠拢的方式来判断,前后指针所指的值如果有不相等的则不是回文。例如abcca,第一次判断前后两个a,通过,接着往下判断b和c,发现不相等,返回false表示非回文。然而该题需要判断的是链表,且是单向链表,所以需要思维转换一下。

思路

方法一:

  1. 将链表的值存入数组
  2. 左右指针向中间靠拢检查回文

Untitled 1.png

这个方法不难想,先遍历链表并在过程中将值存入数组中。然后通过普通的左右指针方法即能可判断回文了。但该方法需要额外的空间,我们可以通过方法二来进一步优化空间复杂度。

复杂度:时间O(n)、空间O(n)

方法二:

  1. 快慢指针找到中间结点
  2. 翻转中间结点以右的链表
  3. 左右指针分别向中间靠拢检查回文

Untitled 2.png

在实现这个方法前,建议把876. 链表的中间结点206. 反转链表完成了。图中虽然分为奇偶两种情况来讨论,但代码实现可以覆盖这两种情况,即找到中间结点之后再翻转。这里注意下第3步左右指针向中间靠拢的循环结束条件为左右指针head或pre为null 的时候即可。

复杂度:时间O(n)、空间O(1)

代码实现-Java

方法一:

class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode node = head;
        List<Integer> lst = new ArrayList<>();
        // 遍历链表并存入数组中
        while (node != null) {
            lst.add(node.val);
            node = node.next;
        }
	// 左右指针向中间靠拢检查回文
        int left = 0, right = lst.size()-1;
        while(left < right) {
            if (lst.get(left) != lst.get(right)) return false;
            left++;right--;
        }
        return true;
    }
}

方法二:

class Solution {
    public boolean isPalindrome(ListNode head) {
        // 快慢指针找中间结点
        ListNode fast = head, slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        // 翻转中间结点之后的链表
        ListNode pre = null;
        while (slow != null) {
            ListNode tmp = slow.next;
            slow.next = pre;
            pre = slow;
            slow = tmp;
        }
        // 左右指针向中间靠拢检查回文
        while (head != null && pre != null) {
            if (head.val != pre.val) return false;
            head = head.next;
            pre = pre.next;
        }
        return true;
    }
}