LeetCode第234题 回文链表



问题描述:

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

示例 1:

输入: 1->2
输出: false

示例 2:

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


解题思路:

解法一:
   可以使用栈先进后出的特点进行解题,遍历链表将所有元素进行压栈,然后再从头遍历一次链表,与栈弹出的节点进行对比,看是否相等。需要注意的是比较的是节点的value值是否相等,而不是比较两个节点是否相等。

解法二:
   解法一的空间复杂度为o(n),为了使空间复杂度为o(1),可以使用快慢指针拆分链表为两段然后进行比较。参考文章:LeetCode官方题解

我们可以将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,但是使用该函数的人通常不希望链表结构被更改。

该方法虽然可以将空间复杂度降到
O(1),但是在并发环境下,该方法也有缺点。在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。

算法

整个流程可以分为以下五个步骤:

扫描二维码关注公众号,回复: 12478286 查看本文章
  1. 找到前半部分链表的尾节点。
  2. 反转后半部分链表。
  3. 判断是否回文。
  4. 恢复链表。
  5. 返回结果。

执行步骤一,我们可以计算链表节点的数量,然后遍历链表找到前半部分的尾节点。

我们也可以使用快慢指针在一次遍历中找到:慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。通过慢指针将链表分为两部分。

若链表有奇数个节点,则中间的节点应该看作是前半部分。

步骤二可以使用「206. 反转链表」问题中的解决方法来反转链表的后半部分。

步骤三比较两个部分的值,当后半部分到达末尾则比较完成,可以忽略计数情况中的中间节点。

步骤四与步骤二使用的函数相同,再反转一次恢复链表本身。



代码实现:

解法一:

    public boolean isPalindrome(ListNode head) {
    
    
        Stack<ListNode> stack = new Stack<>();
        ListNode t = head;
        while(t!=null){
    
    
            stack.push(t);
            t = t.next;
        }
        t = head;
        while (t!=null && !stack.isEmpty()){
    
    
            if(t.val != stack.pop().val){
    
    
                return false;
            }
            t = t.next;
        }
        return true;
    }

提交结果:
在这里插入图片描述

解法二:

class Solution {
    
    
        public boolean isPalindrome(ListNode head) {
    
    
        if (head == null) {
    
    
            return true;
        }

        // 找到前半部分链表的尾节点并反转后半部分链表
        ListNode firstHalfEnd = endOfFirstHalf(head);
        ListNode secondHalfStart = reverseList(firstHalfEnd.next);

        // 判断是否回文
        ListNode p1 = head;
        ListNode p2 = secondHalfStart;
        boolean result = true;
        while (result && p2 != null) {
    
    
            if (p1.val != p2.val) {
    
    
                result = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }        

        // 还原链表并返回结果
        firstHalfEnd.next = reverseList(secondHalfStart);
        return result;
    }

    private 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;
    }

    private 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;
    }

}

提交结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/HC199854/article/details/113793942