leetcode 234.回文链表

leetcode 234.回文链表

题目描述

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

示例 1:

输入: 1->2
输出: false

示例 2:

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

进阶:

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

解题思路

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

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

代码如下:

/**
 * 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) 的方法解题。对于一个回文数组的话,可以使用两个指针,从两端向中间走,当两个指针相遇的时候,表示是一个回文数组。那么对于一个链表,可以把链表改成下图的结构。
在这里插入图片描述

从上图可以看出,把原来的链表从中间开始反转,并且中间元素指向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;
    }
};

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
在这里插入图片描述

发布了153 篇原创文章 · 获赞 201 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/EngineerHe/article/details/104188397
今日推荐