【一次过】Lintcode 223. 回文链表

该博客探讨如何在O(n)时间和O(1)额外空间内检查链表是否为回文。作者提供了两种解题思路:一是使用快慢指针找到中点,并利用栈存储前半段链表的元素进行比较;二是不使用栈,而是翻转链表的后半段,直接进行回文比较。两种方法都考虑了链表长度为奇数和偶数的情况。
摘要由CSDN通过智能技术生成

设计一种方式检查一个链表是否为回文链表。

样例

1->2->1 就是一个回文链表。

挑战

O(n)的时间和O(1)的额外空间。


解题思路1:

链表比字符串难的地方就在于不能通过坐标来直接访问,而只能从头开始遍历到某个位置。那么根据回文串的特点,我们需要比较对应位置的值是否相等,那么我们首先需要找到链表的中点,这个可以用快慢指针来实现,原理是fast和slow两个指针,每次快指针走两步,慢指针走一步,等快指针走完时,慢指针的位置就是中点。我们还需要用栈,每次慢指针走一步,都把值存入栈中,等到达中点时,链表的前半段都存入栈中了,由于栈的后进先出的性质,就可以和后半段链表按照回文对应的顺序比较了。

需要注意考虑链表数目为奇数与偶数的两种情况,这两种情况处理方法略有不同,具体见代码:

/**
 * Definition of singly-linked-list:
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *        this->val = val;
 *        this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: A ListNode.
     * @return: A boolean.
     */
    bool isPalindrome(ListNode * head)
    {
        // write your code here
        if(head == NULL || head->next == NULL)
            return true;
        
        ListNode * slow = head;
        ListNode * fast = head;
        
        stack<int> stk;//装链表前半部分元素,不包括中间元素
        stk.push(slow->val);
        
        //快慢指针寻找链表中间元素,如果链表数目为奇数,slow指向正中间元素,如为偶数,slow指向中间偏左一位置元素
        while(fast->next != NULL && fast->next->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
            stk.push(slow->val);
        }
        
        //如果链表数目为奇数,此时stk装了中间元素,所以要剔除掉,维持其性质
        if(fast->next == NULL)
            stk.pop();

        //栈中元素与链表后半部分一位一位比较即可
        while(slow->next != NULL)
        {
            slow = slow->next;
            
            if(slow->val != stk.top())
                return false;

            stk.pop();
        }
        
        return true;
    }
};

解题思路2:

这道题的挑战让我们用O(1)的空间,那就是说我们不能使用stack了,那么如果代替stack的作用呢,用stack的目的是为了利用其后进先出的特点,好倒着取出前半段的元素。那么现在我们不用stack了,如何倒着取元素呢。我们可以在找到中点后,将后半段的链表翻转一下,翻转部分链表参见:Lintcode 36. 翻转链表 II。这样我们就可以按照回文的顺序比较了,代码如下:

/**
 * Definition for ListNode
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */

public class Solution {
    /**
     * @param head: A ListNode.
     * @return: A boolean.
     */
    public boolean isPalindrome(ListNode head) {
        // write your code here
        if(head == null)
            return true;
        
        //快慢指针寻找链表中间元素,如果链表数目为奇数,slow指向正中间元素,如为偶数,slow指向中间偏左一位置元素
        ListNode slow = head;
        ListNode fast = head;
        
        while(fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        
        //拆分链表[head...slow]为前半部分,(slow, null)为后半部分
        //node1指向前半部分的头节点,node2指向后半部分的头节点
        ListNode node2 = slow.next;
        slow.next = null;
        ListNode node1 = head;
        
        //对后半部分链表翻转
        ListNode pre = null;
        ListNode cur = node2;
        
        while(cur != null){
            ListNode next = cur.next;
            
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        
        //翻转后pre为后半部分根节点
        //依次比较节点值大小
        while(pre != null && node1 != null){
            if(pre.val != node1.val)
                return false;
            
            pre = pre.next;
            node1 = node1.next;
        }
        
        return true;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值