234. Palindrome Linked List

目录

一、题目描述

方法一、使用栈

方法二、将链表全部结点值复制到数组,再用双指针法

方法三、递归法逆序遍历链表

方法四、快慢指针+反转链表


一、题目描述

234. Palindrome Linked List

方法一、使用栈

需要遍历两次。时间复杂度O(n),空间复杂度O(n)。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        stack<int> S;
        ListNode* cur = head;
        while(cur){
            S.push(cur->val);
            cur = cur->next;
        }
        cur = head;
        while(cur){
            if(cur->val != S.top()){
                return false;
            }
            cur = cur->next;
            S.pop();
        }
        return true;
    }
};

方法二、将链表全部结点值复制到数组,再用双指针法

也是需要遍历两次,时间复杂度O(n)。空间复杂度O(n)。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int> nums;
        nums.reserve(100000);
        ListNode* cur = head;
        while(cur){
            nums.push_back(cur->val);
            cur = cur->next;
        }
        int left = 0;
        int right = nums.size()-1;
        while(left<right){
            if(nums[left]!=nums[right])
                return false;
            left++;
            right--;
        }
        return true;
    }
};

方法三、递归法逆序遍历链表

可以用递归法逆序遍历链表。用全局变量正序遍历链表。这样就实现了同时从两端遍历链表。

时间复杂度O(n)。递归栈的深度是n,所以空间复杂度还是O(n)。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    ListNode* forward = nullptr;//从链表头向链表尾正向遍历的指针
public:
    bool isPalindrome(ListNode* head) {
        forward = head;
        //题目已经保证head不为nullptr,至少有一个结点
        return recursiveCheck(head);
    }

    //用递归来逆序遍历链表
    bool recursiveCheck(ListNode* cur){
        if(cur->next){
            if(!recursiveCheck(cur->next))
                return false;
        }

        if(cur->val != forward->val)
            return false;
        forward = forward->next;
        return true;
    }
};

方法四、快慢指针+反转链表

将链表后半部分反转。然后同时遍历前半部分和后半部分,逐个比较。

第一步,用快慢指针法找到链表后半部分的开头结点。如果结点个数是奇数,则正中间的结点算作后半部分的开头也可以。参考leetcode 876. 链表的中间结点-CSDN博客

第二步,反转后半部分链表。参考leetcode 206. 反转链表-CSDN博客

第三步,同时遍历前半部分和后半部分,判断是否回文。

第四步,恢复原链表。

第五步,返回结果。

时间复杂度O(n)。空间复杂度O(1)。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast&&fast->next){
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode* middle = slow;

        //把链表后半部分反转
        ListNode* reveredRight = reverse(middle);
        ListNode* right = reveredRight;
        ListNode* left = head;
        bool res = true;
        while(left != middle){
            if(left->val != right->val){
                res = false;
                break;
            }
            left = left->next;
            right = right->next;
        }

        //恢复原链表
        reverse(reveredRight);
        return res;
    }

    ListNode* reverse(ListNode* head){
        ListNode* pre = nullptr;
        ListNode* cur = head;
        ListNode* nex = nullptr;
        while(cur){
            nex = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nex;
        }
        return pre;
    }
};
相关推荐
努力努力再努力wz2 小时前
【内存管理与高并发内存池系列】从 mmap 到 malloc:文件映射、匿名映射与 glibc 内存分配机制详解
linux·c语言·数据结构·数据库·c++·qt·链表
不会就选b6 小时前
数据结构之链表OJ题(中)
数据结构·链表
兰令水6 小时前
leecodecode【区间DP+树形DP】【2026.6.10打卡-java版本】
java·算法·leetcode
sugar__salt7 小时前
深入吃透前端线性数据结构:数组、栈、队列、链表核心原理与实战
前端·数据结构·链表
8Qi87 小时前
LeetCode 4:寻找两个正序数组的中位数 —— 二分查找法
java·算法·leetcode·职场和发展·二分查找
8Qi87 小时前
LeetCode 32:最长有效括号 —— 栈 + 标记法 题解
java·数据结构·算法·leetcode·职场和发展··括号匹配
Tairitsu_H7 小时前
[LC优选算法#3] 滑动窗口 | 将x减到0的最⼩操作数 | ⽔果成篮 | 字⺟异位词
c++·算法·leetcode·滑动窗口
洛水水8 小时前
【力扣100题】76.搜索插入位置
数据结构·算法·leetcode
wabs6669 小时前
关于动态规划【力扣343.整数拆分的递推公式怎么理解?】
算法·leetcode·动态规划
FuckPatience9 小时前
C# 链表元素的引用地址分析
链表·c#