• 【数据结构】链表经典oj


    目录

    🍍一、链表的回文结构

    🍍二、输入两个链表,找出第一个相交节点

    思路一(暴力解法)

     思路二(时间复杂度更优解)

    🍍三、判断链表中是否有环

    🍉思路

    🍉拓展


    🍍一、链表的回文结构

    以下面这个链表为例子:

    由于单向链表是不可往前回朔的,所以我们无法将从后往前对比。

    我们可以将后面半段,先反转一次。

     再通过两个指针进行对比,第二个指针是链表的中间节点,我们需要找到这个中间节点。

      

     接下来附上两段代码,

    寻找中间节点:

    1. struct ListNode* middleNode(struct ListNode* head)
    2. {
    3. struct ListNode *slow=head,*fast=head;
    4. while(fast!=NULL&&fast->next!=NULL)
    5. {
    6. fast=fast->next->next;
    7. slow=slow->next;
    8. }
    9. return slow;
    10. }

    反转链表:

    1. struct ListNode* reverseList(struct ListNode* head){
    2. struct ListNode * prev,*cur,*next=NULL;
    3. prev=NULL;
    4. cur=head;
    5. next=NULL;
    6. while(cur)
    7. {
    8. next=cur->next;
    9. cur->next=prev;
    10. //迭代
    11. prev=cur;
    12. cur=next;
    13. }
    14. return prev;
    15. }

    上面这两个代码实直接从前面的题目摘下来的,链表的题目的背景一般是一样的,因此是适用的。

    答案如下:

    1. struct ListNode* middleNode(struct ListNode* head)
    2. {
    3. struct ListNode *slow=head,*fast=head;
    4. while(fast!=NULL&&fast->next!=NULL)
    5. {
    6. fast=fast->next->next;
    7. slow=slow->next;
    8. }
    9. return slow;
    10. }
    11. struct ListNode* reverseList(struct ListNode* head){
    12. struct ListNode * prev,*cur,*next=NULL;
    13. prev=NULL;
    14. cur=head;
    15. next=NULL;
    16. while(cur)
    17. {
    18. next=cur->next;
    19. cur->next=prev;
    20. //迭代
    21. prev=cur;
    22. cur=next;
    23. }
    24. return prev;
    25. }
    26. bool chkPalindrome(ListNode* A)
    27. {
    28. ListNode *p1=A;
    29. ListNode *mid=middleNode(A);
    30. ListNode *p2=reverseList(mid);
    31. while(p1&&p2)
    32. {
    33. if(p1->val!=p2->val)
    34. return false;
    35. p1=p1->next;
    36. p2=p2->next;
    37. }
    38. return true;
    39. }

    🍍二、输入两个链表,找出第一个相交节点

    思路一(暴力解法)

    原链表我们可以表达如一下形式

    想要找到c1节点,我们只需要在b链表中查找a链表中第一个与b链表的共同节点。

    1. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    2. struct ListNode *pa=headA,* pb=headB;
    3. while(pb)
    4. {
    5. pa=headA;
    6. while(pa)
    7. {
    8. if(pb==pa)
    9. return pb;
    10. pa=pa->next;
    11. }
    12. pb=pb->next;
    13. }
    14. return NULL;
    15. }

     思路二(时间复杂度更优解)

    我们现将这两个链表便利一遍,得到两个链表的长度,然后再将长的那个链表先走几步,这个步数为这两个链表的长度之差。 

    变成下面这样,这样再次将两个链表遍历,遇到的第一个相同节点就是答案。

    1. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    2. struct ListNode *pa=headA,*pb=headB,* cura=headA,* curb=headB;
    3. int lena=1,lenb=1;
    4. while(cura->next!=NULL)
    5. {
    6. lena++;
    7. cura=cura->next;
    8. }
    9. while(curb->next!=NULL)
    10. {
    11. lenb++;
    12. curb=curb->next;
    13. }
    14. if(cura!=curb)//要是两个链表的尾结点不相同的话说明不是相交链表
    15. return NULL;
    16. if(lenb>lena)
    17. {
    18. for(int i=1;i<=lenb-lena;i++)
    19. {
    20. pb=pb->next;
    21. }
    22. }
    23. else
    24. {
    25. for(int i=1;i<=lena-lenb;i++)
    26. {
    27. pa=pa->next;
    28. }
    29. }
    30. while(pa!=pb)
    31. {
    32. pa=pa->next;
    33. pb=pb->next;
    34. }
    35. return pa;
    36. }

    这就是两个方法的差距:

    🍍三、判断链表中是否有环

    题目中的环指的是如下图的一个节奏,这个链表在实际应用中是没什么用的,这里只是为了用来锻炼我们的思维。

    🍉思路

    设置快慢指针,要是原本走在前面的指针都能与慢指针碰面,就说明快指针陷入了循环。

    这一题里我们指能将快指针速度设置为慢指针的二倍(后面会有讲解)。

    1. bool hasCycle(struct ListNode *head) {
    2. struct ListNode * fast=head,* slow=head;
    3. while(fast&&fast->next)
    4. {
    5. fast=fast->next->next;
    6. slow=slow->next;
    7. if(slow==fast)
    8. return true;
    9. }
    10. return false;
    11. }

    🍉拓展

    fast一次走2步,slow一次走1步,fast会不会错过slow

    fast一次走3步,slow一次走1步,fast会不会错过slow

    fast一次走M步,slow一次走N步,fast会不会错过slow(M>N)

    以下面这个链表为例,快慢指针都已经进入环中,且slow与fast相聚N个节点。

     这里我们需要通过相对速度来理解这个问题。

    fast一次走2步,slow一次走1步,他们的相对速度为1。

    当相距距离为0时,就说明这两个指针相遇了,说明fast一次走2步,slow一次走1步这种情况是不会错过的。

    fast一次走3步,slow一次走1步,他们的相对速度为2。

    得到以下的情况:

     我们可以看出,当N为偶数的时候才会相遇,当他们错过的时候,fast只会领先一个节点。

    这时候他们相距C-1,C为环的总结点个数。所以当C-1为偶数时这种情况才不会错过

    谁都不可能和谁在一起一辈子。人就是这样,必须去习惯失去。——《秒速五厘米》 

  • 相关阅读:
    IPv4用的好好的,为什么我们要换IPv6?
    某985证书站挖掘记录
    【论文阅读】PSDF Fusion:用于动态 3D 数据融合和场景重建的概率符号距离函数
    通讯网关软件011——利用CommGate X2ODBC实现DDE数据转入ODBC
    html通过使用图像源的协议(protocol)相对 URL 来防止安全/不安全错误
    第四部分:Spdlog日志库的核心组件分析-logger
    深入了解JavaScript中的AJAX和HTTP请求
    优雅的记录日志,拒绝打印模糊信息导致bug定位难
    DSPE-PEG-FITC,Fluorescein-PEG-DSPE,修饰性PEG磷脂-聚乙二醇-荧光素
    安装TPDSS
  • 原文地址:https://blog.csdn.net/qq_64484137/article/details/126333160