• 链表OJ练习(2)


    一、分割链表

    题目介绍:

    思路:创建两个链表,ghead尾插大于x的节点,lhead尾插小于x的节点。先遍历链表。最后将ghead尾插到lhead后面,将大小链表链接。

              我们需要在创建两个链表指针,指向两个链表的头节点,用这两个指针标记lhead和ghead的尾结点,方便与尾插。

    注:极端边界场景:所有值都小于x;   所有值都大于x;  空链表。

    1. /*
    2. struct ListNode {
    3. int val;
    4. struct ListNode *next;
    5. ListNode(int x) : val(x), next(NULL) {}
    6. };*/
    7. class Partition {
    8. public:
    9. ListNode* partition(ListNode* pHead, int x)
    10. {
    11. ListNode* gtail, * ghead, * ltail, * lhead;
    12. gtail = ghead = (struct ListNode*)malloc(sizeof(struct ListNode));
    13. ltail = lhead = (struct ListNode*)malloc(sizeof(struct ListNode));
    14. struct ListNode* cur = pHead;
    15. while (cur)
    16. {
    17. if (cur->val < x)
    18. {
    19. ltail->next = cur;
    20. ltail = ltail->next;
    21. }
    22. else
    23. {
    24. gtail->next = cur;
    25. gtail = gtail->next;
    26. }
    27. cur = cur->next;
    28. }
    29. ltail->next = ghead->next;
    30. gtail->next = NULL;
    31. struct ListNode* newhead = lhead->next;
    32. free(lhead);
    33. free(ghead);
    34. return newhead;
    35. }
    36. };

     二、回文链表

    题目介绍:

    思路:先找到中间节点,可以利用快慢指针找到中间节点,然后将中间节点后面的节点翻转,在和中间节点前面的链表依次比较,如果全部相同则是回文链表否则不是。

    1. /*
    2. struct ListNode {
    3. int val;
    4. struct ListNode *next;
    5. ListNode(int x) : val(x), next(NULL) {}
    6. };*/
    7. //struct ListNode* middleNode(struct ListNode* head)
    8. {
    9. struct ListNode* falst;
    10. struct ListNode* slow;
    11. falst = head;
    12. slow = head;
    13. while (falst && falst->next)
    14. {
    15. slow = slow->next;
    16. falst = falst->next->next;
    17. }
    18. return slow;
    19. }
    20. struct ListNode* reverseList(struct ListNode* head)
    21. {
    22. struct ListNode* cur = head;
    23. struct ListNode* newhead = NULL;
    24. while (cur)
    25. {
    26. struct ListNode* next = cur->next;
    27. //头插
    28. cur->next = newhead;
    29. newhead = cur;
    30. cur = next;
    31. }
    32. return newhead;
    33. }
    34. class PalindromeList
    35. {
    36. public:
    37. bool chkPalindrome(ListNode* head)
    38. {
    39. //找到中间节点,将中间节点后面的链表翻转,有第一个和中间节点比较,并依次后移,若全部相同,则为回文链表,反之不是。
    40. struct ListNode* mid = middleNode(head);
    41. struct ListNode* rmid = reverseList(mid);
    42. while (rmid && mid)
    43. {
    44. if (rmid->val != head->val)
    45. {
    46. return false;
    47. }
    48. head = head->next;
    49. rmid = rmid->next;
    50. }
    51. return true;
    52. }
    53. };

    三、找公共点

    题目介绍:

    思路:先遍历两个链表,计算出两个链表的长度,让后计算出两个链表的长度差k,将长的链表先往前走k步,然后将两个链表指针同时后移,找到第一个相同的节点就是相交节点。

    注:需要考虑到空链表,给链表判空,若空headA和headB其中一个为空返回NULL。

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
    9. {
    10. struct ListNode* curA = headA;
    11. struct ListNode* curB = headB;
    12. int lenA = 1;
    13. int lenB = 1;
    14. if(headA==NULL||headB==NULL)
    15. {
    16. return NULL;
    17. }
    18. while (curA->next)
    19. {
    20. curA = curA->next;
    21. lenA++;
    22. }
    23. while (curB->next)
    24. {
    25. curB = curB->next;
    26. lenB++;
    27. }
    28. if (curA != curB) //没有交点
    29. {
    30. return false;
    31. }
    32. int gap = abs(lenA - lenB);
    33. struct ListNode* falst = headA;
    34. struct ListNode* slow = headB;
    35. if (lenA < lenB)
    36. {
    37. falst = headB;
    38. slow = headA;
    39. }
    40. while (gap--)
    41. {
    42. falst = falst->next;
    43. }
    44. while (slow != falst)
    45. {
    46. slow = slow->next;
    47. falst = falst->next;
    48. }
    49. return slow;
    50. }

    四、判断是否是环形链表

    题目介绍:

    思路:还是利用快慢指针,当慢指针往前走一步,快指针往前走两步,在一个环中,每次他们的距离就减少一,如果有环,就一定能追上。如果没追上则没有环。

    用快指针遍历。

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. bool hasCycle(struct ListNode *head)
    9. {
    10. struct ListNode *falst=head;
    11. struct ListNode *slow=head;
    12. while(falst&&falst->next)
    13. {
    14. falst=falst->next->next;
    15. slow=slow->next;
    16. if(falst==slow)
    17. {
    18. return true;
    19. }
    20. }
    21. return false;
    22. }

    五、寻找环形链表的入环节点

    题目描述:

    思路1:假设链表带环,头节点head与入环节点的距离为L,入环节点与相遇点的距离为D,环的大小为C,如下图:

    fast从头节点到相遇点:L + D + kC,其中k为正整数,表示在快慢指针相遇前fast所走圈数

    slow从头节点到相遇点:L + D

    又由于fast每次走两步,slow每次走一步,以上二式可以建立起联系:

    L + D + kC = 2 * (L + D)

    L = kC - D = (k - 1) * C + C - D     

    所以可以得出结论:一个指针从相遇点开始走,一个指针从链表头开始走,则这两个指针一定会在入环节点处相遇。

    1. struct ListNode *detectCycle(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(fast == slow)
    8. {
    9. //找相遇点meetNode
    10. struct ListNode* meetNode = fast;
    11. //相遇点可能就是入环节点
    12. if(meetNode == head)
    13. return head;
    14. //meetNode和head开始每次走一步,直到相遇
    15. while(head && meetNode)
    16. {
    17. meetNode = meetNode->next;
    18. head = head->next;
    19. //当相遇时即为入环节点
    20. if(meetNode == head)
    21. return meetNode;
    22. }
    23. }
    24. }
    25. return NULL;
    26. }

    思路2:我们可以在相遇点将链表断开,找到如节点就相当于找到两个链表的交点。

    找两个链表的交点我们可以参考题目三

    1. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
    2. {
    3. struct ListNode *curA=headA;
    4. struct ListNode *curB=headB;
    5. int lenA=1;
    6. int lenB=1;
    7. while(curA->next)
    8. {
    9. curA=curA->next;
    10. lenA++;
    11. }
    12. while(curB->next)
    13. {
    14. curB=curB->next;
    15. lenB++;
    16. }
    17. if(curA!=curB) //没有交点
    18. {
    19. return false;
    20. }
    21. int gap=abs(lenA-lenB);
    22. struct ListNode *falst=headA;
    23. struct ListNode *slow=headB;
    24. if(lenA<lenB)
    25. {
    26. falst=headB;
    27. slow=headA;
    28. }
    29. while(gap--)
    30. {
    31. falst=falst->next;
    32. }
    33. while(slow!=falst)
    34. {
    35. slow=slow->next;
    36. falst=falst->next;
    37. }
    38. return slow;
    39. }
    40. struct ListNode *detectCycle(struct ListNode *head)
    41. {
    42. struct ListNode *fast=head;
    43. struct ListNode *slow=head;
    44. while(fast&&fast->next)
    45. {
    46. slow=slow->next;
    47. fast=fast->next->next;
    48. if(slow==fast) //相遇了
    49. {
    50. struct ListNode *meet=slow; //将环断开
    51. struct ListNode *newhead=meet->next;
    52. meet->next=NULL;
    53. return getIntersectionNode(head,newhead); //找两个链表的交点
    54. }
    55. }
    56. return NULL;
    57. }
  • 相关阅读:
    深入浅出RVO、NRVO以及std::move的策略与影响
    【LC简单】704. 二分查找
    Java 常用Set集合和常用Map集合
    ChatGPT-4o 有何特别之处?
    云原生中间件RocketMQ(二)源码包结构和集群架构模型
    一、excel转pdf格式jacob.jar
    如何通过日志恢复被删除的数据
    每日一题:Spring 框架中都用到了哪些设计模式❓
    解析csv文件,读取百万级数据
    聊聊Jasypt的StandardPBEByteEncryptor
  • 原文地址:https://blog.csdn.net/m0_69323023/article/details/132642843