练题100天——DAY44:回文链表 ★★☆☆☆

今天是休息日,所以有时间练一道题。

最近也在学习数据库,之后会更新一个图书管理系统的完整实现。

题目

234. 回文链表 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表(回文序列是向前和向后读都相同的序列)。如果是,返回 true ;否则,返回 false

我的思路

将链表每个结点的val值存放到一个数组中,然后对数组检测其是否"回文"。

这道题最开始想到的是:用两个指针指向链表的头和尾,然后比较链表的头尾值,然后向中间移动指针,不相等返回false,两个指针相遇的过程一直都相等,则返回true,但是题目的链表为单向的,无法直接获取一个结点的前驱结点,所以我想到了将链表各结点的值存放的数组中,利用这个办法实现比较。

创建数组,需要知道长度,所以需要先遍历一次链表,获取结点数作为数组的长度。

然后再次遍历链表,将各结点的值存入到数组中

最后"遍历"数组,判断是否回文

代码
cpp 复制代码
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (head->next == NULL) {
            return true;
        }
        ListNode* p = head;
        int len = 0;
        while (p != NULL) {
            len++;
            p = p->next;
        }
        vector<int> arr(len);
        p = head;
        for (int i = 0; i < len && p != NULL; i++) {
            arr[i] = p->val;
            p = p->next;
        }
        int left = 0, right = len - 1;
        while (left < right) {
            if (arr[left] != arr[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
};

复杂度

n为链表的结点数

时间复杂度:O(n)。三次遍历,第一、二次都是遍历整个链表,时间复杂度为O(n),第三次算是遍历半个链表O(n/2),所以总的时间复杂度为O(n)+O(n)+O(n/2)=O(n)。

空间复杂度:O(n)。数组申请的空间为n。

官方题解

方法一:快慢指针

要想让空间复杂度为O(1),就需要对链表自身做处理,将链表分为前后两部分,因为无法直接获取结点的前驱,所以可以将后半部分链表反转,这样就可以直接比较两部分各个结点的值,比较完成后,将后半部分链表再反转回来即可,因为使用该函数的人并不希望链表结构被改变。

但是该方法也有缺点:在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。

根据以上说明,算法流程可分为以下几步:

1.找到前半部分链表的尾结点

2.反转后半部分链表:

可以直接使用练题100天------DAY43:统计前后缀下标Ⅰ+反转链表-CSDN博客的函数

3.比较结点值,判断是否回文

4.恢复链表

5.返回结果

代码
cpp 复制代码
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (head == nullptr) {
            return true;
        }

        // 找到前半部分链表的尾节点并反转后半部分链表
        ListNode* firstHalfEnd = endOfFirstHalf(head);
        ListNode* secondHalfStart = reverseList(firstHalfEnd->next);

        // 判断是否回文
        ListNode* p1 = head;
        ListNode* p2 = secondHalfStart;
        bool result = true;
        while (result && p2 != nullptr) {
            if (p1->val != p2->val) {
                result = false;
            }
            p1 = p1->next;
            p2 = p2->next;
        }

        // 还原链表并返回结果
        firstHalfEnd->next = reverseList(secondHalfStart);
        return result;
    }

    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr != nullptr) {
            ListNode* nextTemp = curr->next;
            curr->next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }

    ListNode* endOfFirstHalf(ListNode* head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast->next != nullptr && fast->next->next != nullptr) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
};

复杂度

n 指的是链表的大小

时间复杂度:O(n)。

空间复杂度:O(1)。只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)。

方法二:递归

这种方法相较于前面两种方法,更难理解。

这里也只给出代码,感兴趣的可以去官方题解看。

代码
cpp 复制代码
class Solution {
    ListNode* frontPointer;
public:
    bool recursivelyCheck(ListNode* currentNode) {
        if (currentNode != nullptr) {
            if (!recursivelyCheck(currentNode->next)) {
                return false;
            }
            if (currentNode->val != frontPointer->val) {
                return false;
            }
            frontPointer = frontPointer->next;
        }
        return true;
    }

    bool isPalindrome(ListNode* head) {
        frontPointer = head;
        return recursivelyCheck(head);
    }
};
相关推荐
CSharp精选营4 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假7 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠8 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦15 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾16 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q16 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记16 天前
单项不带头不循环链表
数据结构·链表