• 【牛客网】:链表的回文结构(提升)


    🎁个人主页:我们的五年

    🔍系列专栏:每日一练

    🌷追光的人,终会万丈光芒

     

    目录

    🏝问题描述:

    🏝问题分析:

     步骤一:查找链表的中间节点

    步骤二:对包括中间节点以后的节点进行逆置

     步骤三:两个头指针相互往后遍历

    🏝节点为计数时分析:

    🏝最终代码:


     前言:

    这道题在链表中属于较难的题目,但是题目中我们用已经学过得基本步骤去改一下就很简单了,这道题应用的基本步骤就是:

    ●查找链表的中间节点

    ●逆置链表

    这些基本步骤我都放在了这篇文章中:链表必写的四道基础题

    牛客网链接:链表的回文结构_牛客题霸_牛客网

    下面就让我们来看看这道题怎么解决:

    🏝问题描述:

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

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

    测试样例:

    1->2->2->1
    返回:true

    🏝问题分析:

    假如上面是一个双链表,我们只要那到链表的头节点和尾节点,然后两个头都往中间进行遍历,如果出现val不相等,我们就返回false,最后没有提前返回false,我们就返回true。

    可惜上面的不是双向链表,但是我们想,单链表我们只能1>2,然后2>1,刚好和1>2和1>2相反,如果我们可以把后面的链表逆置一下,我们就可以做到前面一半也是1>2,后面一半也是1开头,然后1>2,这样就能对上了,下面我们来进行实现

    先以上面的测试用例为例子:

     步骤一:查找链表的中间节点

    我们先查找中间节点,如果节点个数为偶数,那么我们找到的就是中间节点的第二个节点,比如上面的例子我们找到的就是第三个节点。

    查找中间节点的函数的实现:

        struct ListNode* MidNode(struct ListNode* ps)

            {

                struct ListNode* fast=ps;

                struct ListNode* slow=ps;

                if(fast&&fast->next)

                {

                    fast=fast->next->next;

                    slow=slow->next;

                }

                return slow;

            }

    步骤二:对包括中间节点以后的节点进行逆置

    实现函数:

        ListNode* reverselist(ListNode* ps)

        {

            ListNode* newhead=NULL;

            while(ps)

            {

                ListNode* pnext=ps->next;

                ps->next=newhead;

                newhead=ps;

                ps=pnext;

            }

            return newhead;

        }

    对后半段的节点进行逆置以后,链表就变成这样:

     步骤三:两个头指针相互往后遍历

    也就是两个1节点为头,然后每走一步,比较两个节点的val。如果不相同我们就返回false,如果相同就一直一直往后面走,走到一个为NULL为止,走到NULL还没有提前返回false,我们就返回true。

    🏝节点为计数时分析:

    上面我们分析的是节点为偶数个,下面我们来看看节点个数为奇数个时的情况:

     现在我们查找中间节点就是3节点,然后我们进行逆置以后,链表就变成这样了:

    这种情况我们好像我们进行遍历也是没有什么问题的,所以我们只要去查找中间节点,然后进行逆置,然后遍历判断,这道题就完成了。

    🏝最终代码:

    1. /*
    2. struct ListNode {
    3. int val;
    4. struct ListNode *next;
    5. ListNode(int x) : val(x), next(NULL) {}
    6. };*/
    7. class PalindromeList {
    8. public:
    9. //查找中间节点的函数
    10. struct ListNode* MidNode(struct ListNode* ps)
    11. {
    12. struct ListNode* fast=ps;
    13. struct ListNode* slow=ps;
    14. if(fast&&fast->next)
    15. {
    16. fast=fast->next->next;
    17. slow=slow->next;
    18. }
    19. return slow;
    20. }
    21. //逆置链表
    22. ListNode* reverselist(ListNode* ps)
    23. {
    24. ListNode* newhead=NULL;
    25. while(ps)
    26. {
    27. ListNode* pnext=ps->next;
    28. ps->next=newhead;
    29. newhead=ps;
    30. ps=pnext;
    31. }
    32. return newhead;
    33. }
    34. bool chkPalindrome(ListNode* A) {
    35. // write code here
    36. struct ListNode* mid=MidNode(A);
    37. struct ListNode* remid=reverselist(mid);
    38. //进行判断
    39. while(A&&remid)
    40. {
    41. if(A->val!=remid->val)
    42. return false;
    43. A=A->next;
    44. remid=remid->next;
    45. }
    46. return true;
    47. }
    48. };

     总结:

    这道题算是对链表的一个小小提升,这道题目也告诉了我,一定要学好基本的知识点,把基本的知识点用的很熟练以后,才能去解决很难得题目,后期我还会带来很多值得思考,值得我们写一写的题目。如果觉得这篇文章写的好的铁子可以点点关注,祝大家天天开心!

  • 相关阅读:
    多媒体应用设计师 第7章 多媒体数字压缩编码技术基础
    一次Ambari安装记录
    JAVA设计模式-单例模式
    版本控制 | 想要成为硬件设计高手?最佳实践了解一下!
    docker 部署springboot(成功、截图)
    代码随想录算法训练营第五十五天 | 动态规划 part 12 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
    牛客网《剑指offer》专栏刷题练习之数组专精
    [环境]Ubuntu20.04-SLAM测评工具-evo安装
    【408专项篇】C语言笔记-第四章(选择与循环)
    对话ACE第五期:到底什么才是真正的HTAP?
  • 原文地址:https://blog.csdn.net/djdjiejsn/article/details/138222836