每日一恋 - LeetCode 234. Palindrome Linked List(回文链表)

【原题】https://leetcode-cn.com/problems/palindrome-linked-list/description/

题目描述

Given a singly linked list, determine if it is a palindrome.

Example 1:

Input: 1->2
Output: false

Example 2:

Input: 1->2->2->1
Output: true

Follow up:
Could you do it in O(n) time and O(1) space?

分析:
这道题有两个问题:
1、链表的长度。
2、保证时间复杂度为O(n),空间复杂度为O(1)。

第一个问题,题目所给的是一个链表,与给定一个数字相比,最大的不同在于我们不知道链表的长度,就无法简单地得到链表中间的节点。
我们可以设定一个慢指针和一个快指针,慢指针每次都一步,快指针每次走两步。这样一来,当快指针走到最后的时候,慢指针就刚好处于中间位置。

代码如下:

ListNode slow = head;
ListNode fast = head;

// 链表长度为奇数,slow正好在链表中间位置
// 链表长度为偶数,slow正好在链表中间位置偏左一位
// 1->2->2->1
//    ^
//   slow
// 1->2->3->2->1
//       ^
//      slow
while (fast.next != null && fast.next.next != null) {
       slow = slow.next;
       fast = fast.next.next;
}

第二个问题,如何保证时间复杂度为O(n),空间复杂度为O(1)。满足时间复杂度比较容易,遍历一遍链表即可。先不考虑空间复杂度,我们看看有哪些可行的解决方案:

1、数组,遍历链表前半段的时候,将遍历得到的元素存入一个数组中,然后接着遍历后半段,与数组中的元素比较即可。需要n/2的数组空间,空间复杂度为O(n)。
2、栈,由回文很容易想到的数据结构就是栈,先按遍历顺序压入栈,直至中间位置,然后依次出栈与遍历元素比较即可。需要n/2的栈空间,空间复杂度为O(n)。
3、反转链表,即原地将链表反转,不需要额外的储存空间。具体思路是,先将链表后半段原地反转,然后与前半段比较即可。不需要额外的空间,空间复杂度为O(1)。

具体反转链表的方法,见 每日一恋 LeetCode 206. Reverse Linked List (反转链表) 题。

下面贴出具体代码:

public boolean isPalindrome(ListNode head) {

    ListNode slow = head; // 慢指针,一次走一步
    ListNode fast = head; // 快指针,一次走两步

    // 链表长度为 0 或 1 的情况,属于回文数
    if (fast == null || fast.next == null)
        return true;

    // 链表长度为奇数,slow正好在链表中间位置
    // 链表长度为偶数,slow正好在链表中间位置偏左一位
    // 1->2->2->1
    //    ^
    //   slow
    // 1->2->3->2->1
    //       ^
    //      slow
    while (fast.next != null && fast.next.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }

    // 对链表后半段进行反转 LeetCode 206
    ListNode curNode = slow.next; // 后半段链表的第一个节点
    ListNode newHead = null;
    while (curNode != null) {
        ListNode nextNode = curNode.next;
        curNode.next = newHead;
        newHead = curNode;
        curNode = nextNode;
    }

    slow = head;
    fast = newHead; // 结束后newHead为后半段新的头结点,位于原链表的最后一个节点
    // 只考虑后半段是否结束
    // 若链表长度为奇数,前半段会比后半段多出一个节点,这个节点对判断回文没有影响
    // 若为偶数,则前后半段数量相同
    while (fast != null) {
        if (fast.val != slow.val)
            return false;

        fast = fast.next;
        slow = slow.next;
    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值