回文链表【234】

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

方法一:快慢指针

思路:

1.使用快慢指针找到链表的中间点
2.反转中间点后面的链表
3.后半段反转后的链表与上半部分链表比对,如果比对完后都相同,返回true
4.恢复链表,虽然不恢复也可以通过测试,但是尽量不要改变数据结构

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null){return true;}
        ListNode middle = getMiddle(head);
        ListNode pre = reverse(middle.next);
    
        // 判断是否回文
        ListNode p1 = head;
        ListNode p2 = pre;
        boolean result = true;
        while (result && p2 != null) {
            if (p1.val != p2.val) {
                result = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }   
        // 还原链表并返回结果
        middle.next = reverseList(pre);
        return result;
    }

    //快慢指针
    private ListNode getMiddle(ListNode head){
        ListNode slow = head;
        ListNode fast = head;
        while(fast.next != null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    //反转链表
    private ListNode reverse(ListNode head){
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 nn 指的是链表的大小。

  • 空间复杂度:O(1)。我们只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)

方法二:将值复制到数组中后用双指针法

该方法比较简单:
思路:

1.复制链表值到数组列表中。
2.使用双指针法判断是否为回文

代码:

class Solution {
    public boolean isPalindrome(ListNode head) {
       List<Integer> vals = new ArrayList();  

      // 将链表的值复制到数组中
      ListNode currentNode = head;
       while(currentNode != null){
            vals.add(currentNode.val);
            currentNode = currentNode.next;
       }   

       // 使用双指针判断是否回文
       int first = 0;
       int tail = vals.size() - 1;
       while(first < tail){
           if(!vals.get(first).equals(vals.get(tail))){
               return false;
           }
           first++;
           tail--;
       } 
       return true;
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 nn 指的是链表的元素个数。
    - 第一步: 遍历链表并将值复制到数组中,O(n)。
    - 第二步:双指针判断是否为回文,执行了 O(n/2) 次的判断,即 O(n)。
    总的时间复杂度:O(2n) = O(n)O(2n)=O(n)。
  • 空间复杂度:O(n),其中 nn 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。
原文地址:https://www.cnblogs.com/snail-gao/p/13874424.html