欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

leetcode 234.回文链表

程序员文章站 2022-04-17 17:03:59
...

leetcode 234.回文链表

题目描述

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

示例 1:

输入: 1->2
输出: false

示例 2:

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

进阶:

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

解题思路

方法1: 借助额外的空间复杂度,使用栈的方法。

具体方法是,先压榨,这样的话,栈顶的元素就是链表的尾节点,然后再重新遍历一次链表,遍历的过程并弹出栈,如果都相等的话,表示是一个回文链表,否则不是回文链表。使用一个动画说明一下这个过程:
leetcode 234.回文链表

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        stack<int> listStack;
        // 链表为空,或者链表的长度为1
        if(!head && !head->next){
            return true;
        }
        
        ListNode* cur = head; // 定义变量,移动链表节点的位置
        // 把链表中的每一个数压入栈中
        while(cur){
            listStack.push(cur->val); 
            cur = cur->next;
        }
        
        // 遍历链表,并弹出栈,如果所有的数都相等,表示是回文链表
        while(head){
            if(head->val != listStack.top()){
                return false;
            }
            head = head->next;
            listStack.pop();
        }
        return true;
    }
};

方法2: 使用空间复杂度为 O(1)O(1) 的方法解题。对于一个回文数组的话,可以使用两个指针,从两端向中间走,当两个指针相遇的时候,表示是一个回文数组。那么对于一个链表,可以把链表改成下图的结构。
leetcode 234.回文链表

从上图可以看出,把原来的链表从中间开始反转,并且中间元素指向NULL,这样的话就相当于两个指针,从两端开始向中间走,当其中任一个指针指向NULL,就可以判读是一个回文链表,如果遍历过程中发现不相等的元素,表示是非回文链表。

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        // 链表为空,或者链表的长度为1
        if(head == NULL || head->next == NULL){
            return true;
        }
		
        // 定义两个指针,用于定位原始链表两端
        ListNode* p1 = head;
        ListNode* p2 = head;

        // 两个指针,p1走一步,p2走两步,p2走到尾部时,p1走到中间的位置
        while(p2->next!=NULL && p2->next->next!=NULL){
            p1 = p1->next;
            p2 = p2->next->next;
        }
        
        // 从中间位置开始反转链表, 这里为了节省变量,依然使用p1,p2
        p2 = p1->next;  
        p1->next = NULL;
        ListNode* p3 = NULL;  
        // 反转链表
        while(p2 != NULL){
            p3 = p2->next;
            p2->next = p1;
            p1 = p2;
            p2 = p3;
        }
        
        p3 = p1; // 存储链表尾结点,用于恢复原始链表
        p2 = head; 
        bool res = true;
        // 从两端开始遍历
        while(p1 != NULL && p2!=NULL){
            if(p1->val != p2->val){
                res = false;  // 如果不相等,表示非回文
                break;
            }
            p1 = p1->next;
            p2 = p2->next;
        }
        // 恢复原始链表
        p1 = p3->next;
        p3->next = NULL;
        while(p1 != NULL){
            p2 = p1->next;
            p1->next = p3;
            p3 = p1;
            p1 = p2;
        }

        return res;
    }
};

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
leetcode 234.回文链表