• 两个单链表相交的问题


    两链表相交及其第一个节点 

     

    判断有环无环

    判断有无环,如果有环返回第一个入环节点,如果无环返回null

    使用额外空间:Set结构

    沿着指针将a、b、c、d、e、c放入set结构中,每次放入前查看在set集合中是否存在;

    若遍历到null都没有重复节点,那么链表为无环链表;

    若有重复,链表有环,第一个重复的值即为第一个入环节点

    不使用额外空间

    如果一个链表无环,一定能够指向null

    如果一个链表有环,最终它一定在一直循环

    快慢指针:快指针一次走两步,慢指针一次走一步

    如果一个链表无环,快指针先指向null

    如果一个链表有环,快满指针一定会在某一时刻相遇

    (不一定在入环节点相遇并且慢指针在环中转的圈数不超过两圈

    相遇之后,慢指针在原地,快指针回到起点,接下来快慢指针都走一步,两个指针一定会在入环节点相遇(数学证明)

    1. //判断有环无环,有环返回第一个入环节点,无环返回null
    2. public static Node getloopNode(Node head) {
    3. if (head == null || head.next == null || head.next.next == null) {
    4. return null;
    5. }
    6. //快慢指针相遇的时候停止,如果快慢指针都从head出发,开始时相遇,所以快指针先走两步,慢指针走一步
    7. Node slow = head.next;
    8. Node fast = head.next.next;
    9. while (slow != fast) {
    10. if (fast.next == null || fast.next.next == null) {//无环
    11. return null;
    12. }
    13. slow = slow.next;
    14. fast = fast.next.next;
    15. }
    16. fast = head;//回到开头
    17. while (slow != fast) {
    18. slow = slow.next;
    19. fast = fast.next;
    20. }
    21. return slow;
    22. }

    对两个链表分类讨论

    两个链表分别调用getloopNode方法

    两个无环单链表

            loop1 == null        loop2 == null

            不可能如左图所示,单链表只能有一个next指针;如果两链表相交,一定是右图所示

                         

          先遍历两个链表,记录两链表的长度;

          比较链表最后一个Node,如果相等,则两链表相交;若不相等,则两链表不相交

          长链表先走两个链表之间的长度差,之后两链表再一起走,两链表在第一个相交节点处相遇  

    1. //如果两个链表都无环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
    2. public static Node noLoop(Node head1, Node head2) {
    3. if (head1 == null || head2 == null) {
    4. return null;
    5. }
    6. int length1 = 0, length2 = 0;
    7. //遍历链表1
    8. while (head1.next != null) {//链表1在最后一个节点停
    9. length1++;
    10. head1 = head1.next;
    11. }
    12. //遍历链表2
    13. while (head2.next != null) {//链表2在最后一个节点停
    14. length2++;
    15. head2 = head2.next;
    16. }
    17. if (head1 == head2) {//不相交
    18. return null;
    19. } else {
    20. while(head1 != head2){//还没相遇
    21. if (length1 > length2) {//链表1较长
    22. length1--;
    23. head1 = head1.next;
    24. } else if (length1 < length2) {//链表2较长
    25. length2--;
    26. head2 = head2.next;
    27. } else {//长链表先走了差值长度之后,两链表一起走直到相遇
    28. head1 = head1.next;
    29. head2 = head2.next;
    30. }
    31. }
    32. }
    33. return head1;
    34. }

    一个有环单链表,一个无环单链表 

    此种情况两链表不可能相交,一定会有某个节点有两个next指针

    两个有环单链表

                                                          

    情况2:求相交节点 = 两无环单链表求相交节点

                 把入环节点看成结尾,终止节点为loop1==loop2

    情况1和情况3:loop1继续向下走,如果在循环中没有遇到loop2,则两链表不相交;

                             如果在循环的过程中遇到了loop2,则两链表相交

                             返回的结果既可以是loop1,也可以是loop2,两个节点都是两链表的相交节点

    1. //如果两个链表都有环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
    2. //loop1 = getloopNode(head1); loop2 = getloopNode(head2);
    3. public static Node bothLoop(Node head1, Node head2, Node loop1, Node loop2) {
    4. if (loop1 == loop2) {//情况2
    5. int length1 = 0, length2 = 0;
    6. //遍历链表1
    7. while (head1.next != null) {//链表1在最后一个节点停
    8. length1++;
    9. head1 = head1.next;
    10. }
    11. //遍历链表2
    12. while (head2.next != null) {//链表2在最后一个节点停
    13. length2++;
    14. head2 = head2.next;
    15. }
    16. if (head1 == head2) {//不相交
    17. return null;
    18. } else {
    19. while (head1 != head2) {//还没相遇
    20. if (length1 > length2) {//链表1较长
    21. length1--;
    22. head1 = head1.next;
    23. } else if (length1 < length2) {//链表2较长
    24. length2--;
    25. head2 = head2.next;
    26. } else {//长链表先走了差值长度之后,两链表一起走直到相遇
    27. head1 = head1.next;
    28. head2 = head2.next;
    29. }
    30. }
    31. }
    32. return head1;
    33. } else {//情况1和情况3
    34. Node temp = loop1.next;
    35. while (temp != loop1) {//在圈里面遍历
    36. if (temp == loop2) {//遇到loop2,情况3
    37. return loop1;//return loop2;
    38. }
    39. temp = temp.next;
    40. }
    41. return null;//情况1
    42. }
    43. }

    回到题目

    调用 

    1. public static Node getIntersectNode(Node head1,Node head2){
    2. if(head1 == null || head2 == null){
    3. return null;
    4. }
    5. Node loop1 = getloopNode(head1);
    6. Node loop2 = getloopNode(head2);
    7. if(loop1 == null && loop2 == null){
    8. return noLoop(head1,head2);
    9. } else if (loop1 != null && loop2 != null) {
    10. return bothLoop(head1,head2,loop1,loop2);
    11. }else{
    12. return null;
    13. }
    14. }

     全代码

    1. package linkedlist;
    2. public class IntersectLinkedList {
    3. class Node {
    4. public int value;
    5. public Node next;
    6. public Node(int data) {
    7. this.value = data;
    8. }
    9. }
    10. //判断有环无环,有环返回第一个入环节点,无环返回null
    11. public static Node getloopNode(Node head) {
    12. if (head == null || head.next == null || head.next.next == null) {
    13. return null;
    14. }
    15. //快慢指针相遇的时候停止,如果快慢指针都从head出发,开始时相遇,所以快指针先走两步,慢指针走一步
    16. Node slow = head.next;
    17. Node fast = head.next.next;
    18. while (slow != fast) {
    19. if (fast.next == null || fast.next.next == null) {//无环
    20. return null;
    21. }
    22. slow = slow.next;
    23. fast = fast.next.next;
    24. }
    25. fast = head;//回到开头
    26. while (slow != fast) {
    27. slow = slow.next;
    28. fast = fast.next;
    29. }
    30. return slow;
    31. }
    32. //如果两个链表都无环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
    33. public static Node noLoop(Node head1, Node head2) {
    34. if (head1 == null || head2 == null) {
    35. return null;
    36. }
    37. int length1 = 0, length2 = 0;
    38. //遍历链表1
    39. while (head1.next != null) {//链表1在最后一个节点停
    40. length1++;
    41. head1 = head1.next;
    42. }
    43. //遍历链表2
    44. while (head2.next != null) {//链表2在最后一个节点停
    45. length2++;
    46. head2 = head2.next;
    47. }
    48. if (head1 == head2) {//不相交
    49. return null;
    50. } else {
    51. while (head1 != head2) {//还没相遇
    52. if (length1 > length2) {//链表1较长
    53. length1--;
    54. head1 = head1.next;
    55. } else if (length1 < length2) {//链表2较长
    56. length2--;
    57. head2 = head2.next;
    58. } else {//长链表先走了差值长度之后,两链表一起走直到相遇
    59. head1 = head1.next;
    60. head2 = head2.next;
    61. }
    62. }
    63. }
    64. return head1;
    65. }
    66. //如果两个链表都有环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
    67. //loop1 = getloopNode(head1); loop2 = getloopNode(head2);
    68. public static Node bothLoop(Node head1, Node head2, Node loop1, Node loop2) {
    69. if (loop1 == loop2) {//情况2
    70. int length1 = 0, length2 = 0;
    71. //遍历链表1
    72. while (head1.next != null) {//链表1在最后一个节点停
    73. length1++;
    74. head1 = head1.next;
    75. }
    76. //遍历链表2
    77. while (head2.next != null) {//链表2在最后一个节点停
    78. length2++;
    79. head2 = head2.next;
    80. }
    81. if (head1 == head2) {//不相交
    82. return null;
    83. } else {
    84. while (head1 != head2) {//还没相遇
    85. if (length1 > length2) {//链表1较长
    86. length1--;
    87. head1 = head1.next;
    88. } else if (length1 < length2) {//链表2较长
    89. length2--;
    90. head2 = head2.next;
    91. } else {//长链表先走了差值长度之后,两链表一起走直到相遇
    92. head1 = head1.next;
    93. head2 = head2.next;
    94. }
    95. }
    96. }
    97. return head1;
    98. } else {//情况1和情况3
    99. Node temp = loop1.next;
    100. while (temp != loop1) {//在圈里面遍历
    101. if (temp == loop2) {//遇到loop2,情况3
    102. return loop1;//return loop2;
    103. }
    104. temp = temp.next;
    105. }
    106. }
    107. return null;//情况1
    108. }
    109. public static Node getIntersectNode(Node head1,Node head2){
    110. if(head1 == null || head2 == null){
    111. return null;
    112. }
    113. Node loop1 = getloopNode(head1);
    114. Node loop2 = getloopNode(head2);
    115. if(loop1 == null && loop2 == null){
    116. return noLoop(head1,head2);
    117. } else if (loop1 != null && loop2 != null) {
    118. return bothLoop(head1,head2,loop1,loop2);
    119. }else{
    120. return null;
    121. }
    122. }
    123. }
  • 相关阅读:
    PMP每日一练 | 考试不迷路-9.14(包含敏捷+多选)
    windows环境如何查询端口号占用及杀死进程
    小程序长文本限制显示行数
    腾讯云网站备案详细流程_审核时间说明
    配置Flutter开发环境
    线性时间选择(Top K)问题(Java)
    基于Java的4S店汽车商城系统设计与实现(源码+lw+部署文档+讲解等)
    力扣26. 删除有序数组中的重复项
    C语言练习百题之位符号|的使用
    C#使用自定义的泛型节点类 Node<T>实现二叉树类BinaryTree<T>及其方法
  • 原文地址:https://blog.csdn.net/m0_73530538/article/details/132890052