当前位置: 首页 > news >正文

LeetCode每日精进:链表的回文结构

题目链接:链表的回文结构

题目描述:

        对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

        给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:1->2->2->1

返回:true

思路一: 创建新链表保存原链表结点,反转新链表,遍历比较原链表结点

        由于回文结构的特殊性,反转链表中每个结点对应原链表中结点值相同,即反转链表为原链表的深拷贝

        ListNode* pcur = A;
        ListNode *newHead,*newTail;
        newHead = newTail = NULL;
        //创建新链表,复制原链表
        while(pcur)
        {
            if (newHead == NULL)
            {
                newHead = newTail = pcur;
            }
            else{
                newTail->next = pcur;
                newTail = newTail->next;
            }
            pcur = pcur->next;
        }

        首先,创建新链表,复制原链表中的结点。        

        ListNode* n1 = NULL;
        ListNode* n2 = newHead;
        ListNode* n3 = newHead->next;
        while(n2)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if(n3)
                n3 = n3->next;
        }

        反转新链表,代码参考反转链表。

        ListNode* l1 = A;
        ListNode* l2 = n1;
        while(l1)
        {
            if (l1->val != l2->val)
            {
                return false;
            }
            l1 = l1->next;
            l2 = l2->next;
        }
        return true;

        比较新旧链表中对应结点:

        若有一个结点值不相同,则返回false。

        若结点值均相同,循环结束,则返回true。

完整代码:

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        if (A == NULL)
        {
            return true;
        }

        ListNode* pcur = A;
        ListNode *newHead,*newTail;
        newHead = newTail = NULL;
        //创建新链表,复制原链表
        while(pcur)
        {
            if (newHead == NULL)
            {
                newHead = newTail = pcur;
            }
            else{
                newTail->next = pcur;
                newTail = newTail->next;
            }
            pcur = pcur->next;
        }

        //反转链表
        ListNode* n1 = NULL;
        ListNode* n2 = newHead;
        ListNode* n3 = newHead->next;
        while(n2)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if(n3)
                n3 = n3->next;
        }

        //比较新旧链表
        ListNode* l1 = A;
        ListNode* l2 = n1;
        while(l1)
        {
            if (l1->val != l2->val)
            {
                return false;
            }
            l1 = l1->next;
            l2 = l2->next;
        }
        return true;

    }
};

        时间复杂度O(n),由于创建了新链表,空间复杂度为O(n),显然不符合题目要求,需要进一步优化。 

思路二:投机取巧法

        注意到题目所给的链表长度小于等于900,我们可以创建一个可以存放900个整型的数组,将链表的结点值逐一存放在数组中,并用回文数组的判断方式解决,这样就能将空间复杂度降为O(1)。

图示:

        int arr[900] = {0};
        int size = 0;

         除了定义数组arr外,再定义size来记录数组中的有效数据个数。

        while(pcur)
        {
            arr[size++] = pcur->val;
            pcur = pcur->next;           
        }

        遍历链表,将链表中的结点值放在数组中,每放入一次size自增一。

        int left = 0;
        int right = size - 1;
        while(left < right)
        {
            if (arr[left] != arr[right])
            { 
                return false;
            }
            left++;
            right--;
        }

        最后判断数组是否具有回文结构。

完整代码:

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        int arr[900] = {0};
        int size = 0;
        ListNode* pcur = A;
        while(pcur)
        {
            arr[size++] = pcur->val;
            pcur = pcur->next;           
        }
        int left = 0;
        int right = size - 1;
        while(left < right)
        {
            if (arr[left] != arr[right])
            { 
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
};

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

        在题目限制链表结点个数的情况下,这种方法符合题目要求,但若链表个数未被限制呢? 

思路三:快慢指针找链表的中间结点,将中间结点作为头结点,反转链表

        ListNode* slow = A;
        ListNode* fast = A;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
        }

        定义快慢指针找中间结点,参考链表的中间结点,跳出循环后,此时让slow成为新的头结点。

        ListNode* head = slow;
        ListNode* n1 = NULL;
        ListNode* n2 = head;
        ListNode* n3 = head->next;
        while(n2)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if (n3)
                n3 = n3->next;
        }

        再让以head为头结点的链表反转。

图示:

        链表结点个数为偶数:

        链表结点个数为奇数:

        最后,判断回文结构:

        ListNode* left = A;
        ListNode* right = n1;

 

        定义left与right指针分别指向两侧,左右指针向中间移动判断,当右指针为空,循环结束,返回true。

            if (left->val != right->val)
            {
                return false;
            }

         若左右指针所指向的结点值不同,返回false。

完整代码:

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        //找中间结点
        ListNode* slow = A;
        ListNode* fast = A;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
        }

        //反转链表
        ListNode* head = slow;
        ListNode* n1 = NULL;
        ListNode* n2 = head;
        ListNode* n3 = head->next;
        while(n2)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if (n3)
                n3 = n3->next;
        }

        //判断回文
        ListNode* left = A;
        ListNode* right = n1;
        while(right)
        {
            if (left->val != right->val)
            {
                return false;
            }
            left = left->next;
            right = right->next;
        } 
        return true;
    }
};

        这样在链表个数没被限制下,也能使空间复杂度降为O(1),同时时间复杂度为O(n)。         

相关文章:

  • vue框架生命周期详细解析
  • 【含开题报告+文档+PPT+源码】基于spring boot的固定资产管理系统
  • UIView 与 CALayer 的联系和区别
  • Java每日精进·45天挑战·Day18
  • AI Agent未来走向何方?
  • 如何在割接过程中确保服务不中断?
  • 在Spring Cloud项目中集成MySQL、MyBatis-Plus与HikariCP
  • 【设计模式】【行为型模式】命令模式(Command)
  • Docker 安装与配置 Nginx
  • C++20 新特性解析
  • Scrapy:任务队列底层设计详解
  • JSON入门
  • 配置mysql8.0主从同步,并使用PXC实现高可用
  • 【Linux】Socket编程—TCP
  • OpenEuler学习笔记(三十一):在OpenEuler上搭建仓颉语言开发环境
  • 探索后端开发中的异步API:基于Resilience4j与Reactive Programming的高性能设计
  • eval 内置函数用法
  • 三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab)
  • SQL-leetcode—1581. 进店却未进行过交易的顾客
  • 怎么才能DeepSeek批量写作和内容导出?
  • 人民日报钟声:国际社会应共同维护科学溯源的正确方向
  • 200枚篆刻聚焦北京中轴线,“印记”申遗往事
  • 百年传承,再启新程,参天中国迎来2.0时代
  • 青海西宁市城西区副区长于媛媛主动投案,接受审查调查
  • 俄外长:俄将在不损害伙伴关系前提下发展对美关系
  • 交行一季度净利253.72亿元增1.54%,不良率微降