zoukankan      html  css  js  c++  java
  • 求两个链表第一个相交节点


    import java.util.HashSet;

    /**
    * 求两个链表第一个相交节点
    */
    public class FindFirstIntersectNode {

    public Node FindFirstIntersectNode(Node head1, Node head2) {
    if (head1 == null || head2 == null) {
    return null;
    }
    // 入环节点
    Node loop1 = getLoopNode(head1);
    Node loop2 = getLoopNode(head2);
    // 都无环
    if (loop1 == null && loop2 == null) {
    return noLoops(head1, head2);
    } else if (loop1 != null && loop2 != null) {
    return bothLoops(head1, loop1, head2, loop2);
    }
    return null;
    }

    /**
    * 都有环情况下的相交节点
    *
    * @param head1 链表1
    * @param head2 链表2
    */
    private Node bothLoops(Node head1, Node loop1, Node head2, Node loop2) {
    Node cur1 = null;
    Node cur2 = null;
    // 如果同时入环,则相交节点在入环之前或者在入环的点,舍弃环,寻找交点,同都无环的寻找方法
    if (loop1 == loop2) {
    int n = 0;
    cur1 = head1;
    while (cur1 != loop1) {
    n++;
    cur1 = cur1.next;
    }
    cur2 = head2;
    while (cur2 != loop2) {
    n--;
    cur2 = cur2.next;
    }
    cur1 = n >= 0 ? head1 : head2;
    cur2 = cur1 == head1 ? head2 : head1;
    // 链表尾部对齐
    n = Math.abs(n);
    while (n != 0) {
    n--;
    cur1 = cur1.next;
    }
    // 第一个相等的点即为相交节点,若不相交返回null(此处不可能)
    while (cur1 != cur2) {
    cur1 = cur1.next;
    cur2 = cur2.next;
    }
    return cur1;
    }
    // 如果入环节点不同,则节点都在环上,一个节点不动,一个节点往前走一圈,相遇即相交
    cur1 = loop1.next;
    while (cur1 != loop1) {
    if (cur1 == loop2) {
    return loop1;
    }
    cur1 = cur1.next;
    }
    return null;
    }

    /**
    * 都无环情况下的相交节点
    *
    * @param head1 链表1
    * @param head2 链表2
    */
    private Node noLoops(Node head1, Node head2) {
    // 链表长度差值,若相交,则共用链表尾部
    int n = 0;
    Node cur1 = head1;
    while (cur1.next != null) {
    n++;
    cur1 = cur1.next;
    }
    Node cur2 = head2;
    while (cur2.next != null) {
    n--;
    cur2 = cur2.next;
    }
    // 若尾部不一样,不可能相交
    if (cur1 != cur2) {
    return null;
    }
    cur1 = n >= 0 ? head1 : head2; // 谁长,谁的头变成cur1
    cur2 = cur1 == head1 ? head2 : head1; // 谁短,谁的头变成cur2
    // 链表尾部对齐
    while (n != 0) {
    n--;
    cur1 = cur1.next;
    }
    // 第一个相等的点即为相交节点,若不相交返回null(此处不可能)
    while (cur1 != cur2) {
    cur1 = cur1.next;
    cur2 = cur2.next;
    }
    return cur1;
    }

    /**
    * 获取链表的入环节点,如无环,返回null
    * HashSet实现
    *
    * @param head 链表头结点
    * @return 入环节点
    */
    public Node getLoopNode(Node head) {
    if (head == null) {
    return null;
    }
    HashSet<Node> nodeSet = new HashSet<>();
    Node cur = head;
    while (cur != null) {
    if (nodeSet.contains(cur)) {
    return cur;
    }
    nodeSet.add(cur);
    cur = cur.next;
    }
    return null;
    }

    /**
    * 快慢指针
    * 快指针一次走两步,慢指针一次走一步,两个指针相遇之后,让快指针指向头结点并一次走一步,慢指针继续一次走一步,再次相遇的节点即为入环节点
    * 此处已被数学证明是正确的,但是具体的证明过程我并不会
    *
    * @param head 链表头结点
    * @return 入环节点
    */
    public Node getLoopNode2(Node head) {
    if (head == null || head.next == null || head.next.next == null) {
    return null;
    }
    Node slow = head.next;
    Node fast = head.next.next;
    while (slow != fast) {
    if (fast.next == null || fast.next.next == null) {
    return null;
    }
    slow = slow.next;
    fast = fast.next.next;
    }
    fast = head;
    while (fast != slow) {
    fast = fast.next;
    slow = slow.next;
    }
    return fast;
    }

    /**
    * 链表结构
    */
    public static class Node {

    public int value;

    public Node next;

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

    }

    }

    /* 如有意见或建议,欢迎评论区留言;如发现代码有误,欢迎批评指正 */
  • 相关阅读:
    glibc源码下载
    指令查找工具
    ubuntu下ldd,查看程序动态库信息
    gdb使用记录
    找到返回地址(1)
    vim自动格式化
    android 注入so
    Mac下安装m2crypto 解决找不到openssl头文件的错误
    Mac下android studio卡,居然这么解决了。。。。
    git忽略文件
  • 原文地址:https://www.cnblogs.com/laydown/p/12840481.html
Copyright © 2011-2022 走看看