leecode题集 —— 两个可能有环链表相交找交点

两个可能有环链表相交找交点

解题思路

  1. 首先我们先来分析一下无环情况如何找到交点
    1. 首先判断是否相交 --> 两个链表的最后一个节点是否相同,若相同则一定是相交的
    2. 若相交,找交点 --> 将链表差值得出,长链表先走差值这么多,然后两个链表一起走,第一个相等的节点就是交点
  2. 接下来我们分析如何判断链表有环
    思路一、 遍历链表将节点一个一个放入set集合,当放入的节点重复了,就说明有环,若节点走到null说明无环
    思路二、 使用快慢指针,链表有环快慢指针必然会重合,若无环快指针会走到null (ps: 这里的快慢指针指的是快节点走两步,慢节点走一步)
  3. 接下来我们找到链表环的入口节点
    思路一、使用set的方式,找到的节点就是入口节点
    思路二、 使用快慢指针找到重合节点后,快指针从头开始一步一步走,慢指针继续向前,两个指针重合节点就是入口节点
  4. 接着我们分析有环链表相交的情况
    1. 两个链表都有环且不相交
    2. 两个链表都有环相交,交点不在环上,或正好在入口点
    3. 两个链表都有环相交,交点在环上
      第二种情况 --> 这种情况和无环相交类似,只是快节点走到null改为快节点走到环入口点
      第三种情况,第一种情况 --> 找到两个链表的入口点,让一个链表的节点继续走,如果走一圈又走回来了没有碰到另一个入口点说明为情况1,若遇到了说明为情况2

代码

思路梳理清楚之后开始写代码

class Node{
   int value;
    Node next;
    public Node(int value){
        this.value = value;
    }
}

1.首先我们先来分析一下无环情况如何找到交点

private static Node findCrosserPoint(Node node1,Node node2) {
     if(node1 == null || node2 == null) {
          return null;
      }

      Node nodeN = node1;
      Node nodeM = node2;
      int n = 0;
      while (nodeN.next != null){
          n++;
          nodeN = nodeN.next;
      }
      while (nodeM.next != null){
          n--;
          nodeM = nodeM.next;
      }
      if(nodeN != nodeM){
          return null;
      }

      nodeN = n > 0 ? node1 : node2;
      nodeM = nodeN == node1 ? node2 : node1;

	   n = Math.abs(n);
	
    for (int i = 0; i < n; i++) {
         nodeN = nodeN.next;
     }

     while(nodeN != null){
         if(nodeN == nodeM) {
             break;
         }
         nodeN = nodeN.next;
         nodeM = nodeM.next;
     }
      return nodeN;
  }

2/3. 接下来我们分析如何判断链表有环,有环返回入口点,无环返回null

private static Node isCycle(Node node) {
//        思路二。 使用快慢指针,链表有环快慢指针必然会重合,若无环快指针会走到null
        if(node == null || node.next == null || node.next.next == null){
            return null;
        }
        Node nodeF = node.next.next;
        Node nodeS = node.next;

        while(nodeF != nodeS) {
            if(nodeF.next == null || nodeF.next.next == null) {
                return null;
            }
            nodeF = nodeF.next.next;
            nodeS = nodeS.next;
        }

        // 找到入口点
        nodeF = node;

        while(nodeF != nodeS) {
            nodeF = nodeF.next;
            nodeS = nodeS.next;
        }

        return nodeF;
    }

4.我们分析有环链表相交的情况

private static Node findCrosser(Node node1,Node node2,Node loop1,Node loop2) {

        if(node1 == null || node2 == null || loop1 == null || loop2 == null) {
            return null;
        }

        if(loop1 == loop2) {
            // 第二种情况 --> 这种情况和无环相交类似,只是快节点走到null改为快节点走到环入口点
            Node nodeN = node1;
            Node nodeM = node2;
            int n = 0;
            while (nodeN.next != loop1){
                n++;
                nodeN = nodeN.next;
            }
            while (nodeM.next != loop2){
                n--;
                nodeM = nodeM.next;
            }

            nodeN = n > 0 ? node1 : node2;
            nodeM = nodeN == node1 ? node2 : node1;

            n = Math.abs(n);

            for (int i = 0; i < n; i++) {
                nodeN = nodeN.next;
            }

            while(nodeN != null){
                if(nodeN == nodeM) {
                    return nodeN;
                }
                nodeN = nodeN.next;
                nodeM = nodeM.next;
            }
        } else {

            Node node = loop1.next;
            while(node != loop1) {
                if(node == loop2){
                    return node;
                }
                node = node.next;
            }
            return null;
        }

        return null;
    }

5.总方法连接起来

private static Node isCrosser(Node node1,Node node2) {

        Node loop1 = isCycle(node1);
        Node loop2 = isCycle(node2);


        if(loop1 == null && loop2 == null) {
            return findCrosserPoint(node1,node2);
        }

        if(loop1 != null && loop2 != null) {
            return findCrosser(node1,node2,loop1,loop2);
        }
		
		// 一个有环一个无环必然不相交
        return null;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值