算法day04

61 阅读1分钟

1.复制特殊链表(每个节点包括next和random两个指针)

(1)空间复杂度为O(N)的方法
public Node CopyListWithRandom(Node head) {
    if (head == null) return null;
    HashMap<Node, Node> map = new HashMap<>();
    Node next = null;
    Node cur = head;
    while (cur != null) {
        next = cur.next;
        map.put(cur, new Node(cur.val));
        cur = next;
    }
    cur = head;
    while (cur != null) {
        next = cur.next;
        map.get(cur).next = cur.next;
        map.get(cur).random = cur.random != null ? cur.random : null;
        cur = next;
    }
    return map.get(head);
}

(2)空间复杂度为O(1)的方法
public Node CopyListWithRandom1(Node head) {
    if (head == null) return null;
    Node cur = head;
    Node next = null;
    Node rehead = null;
    while (cur != null) {
        next = cur.next;
        rehead = new Node(cur.val);
        rehead.next = next;
        cur.next = rehead;
        cur = next;
    }
    cur = head;
    while (cur!=null){
        next = cur.next.next;
        rehead = cur.next;
        rehead.random = cur.random!=null?cur.random.next:null;
        cur = next;
    }
    cur = head;
    rehead = head.next;
    Node help = null;
    while (cur!=null){
        next = cur.next.next;
        help = cur.next;
        cur.next = next;
        help.next = next!=null?next.next:null;
        cur = next;
    }
    return rehead;
}

2.寻找两个链表的交点(可能有环)

public Node FindFirstInsertNode(Node head1,Node head2){
    if(isLoop2(head1)==null && isLoop2(head2)==null) return FindFirstInsertNode1(head1,head2);
    if(isLoop2(head1)==null&&isLoop2(head2)!=null || isLoop2(head1)!=null && isLoop2(head2)==null)  return null;
    return FindFirstInsertNode2(head1,head2);
}



//判断当前链表是否有环,如果有环返回第一个入环节点,如果没有返回null


public Node isLoop1(Node head){         //  哈希表法,空间复杂度O(N)
    if (head==null||head.next==null) return null;
    HashSet<Node> hashSet = new HashSet<>();
    Node cur = head;
    while (cur!=null){
        if(hashSet.contains(cur)){
            return cur;
        }else {
            hashSet.add(cur);
        }
        cur = cur.next;
    }
    return null;
}

public Node isLoop2(Node head){         //双指针法,空间复杂度O(1)
    if(head == null||head.next==null) return null;
    Node fast = head.next.next;
    Node slow = head.next;
    while (fast!=slow){
        if (fast==null || slow==null || fast.next==null){
            return null;
        }
        fast = fast.next.next;
        slow = slow.next;
    }
    fast = head;
    while (fast!=slow){
        fast = fast.next;
        slow = slow.next;
    }
    return fast;
}

public Node FindFirstInsertNode1(Node head1,Node head2){        //  如果两个都是无环的,调用这个方法
    if(head1==null || head2==null) return null;
    Node cur1 = head1;
    Node cur2 = head2;
    int len1 = 0;
    int len2 = 0;
    while (cur1.next!=null){
        cur1 = cur1.next;
        len1++;
    }
    while (cur2.next!=null){
        cur2 = cur2.next;
        len2++;
    }
    if(cur1!=cur2) return null;         // 如果末尾节点不是同一个,两个链表一定不相交,直接返回null
    cur1 = len1>len2?head1:head2;       //cur1指向较长链表的头节点
    cur2 = len1>len2?head2:head1;       //cur指向较短的
    int len = Math.abs(len1-len2);
    while (len>0){                      //  cur1先走
        cur1 = cur1.next;
        len--;
    }
    while (cur1!=cur2){
        cur1 = cur1.next;
        cur2 = cur2.next;
    }

    return cur1;
}

public Node FindFirstInsertNode2(Node head1,Node head2){     // 如果两个都有环
    Node n1 = isLoop2(head1);
    Node n2 = isLoop2(head2);
    Node cur1 = head1;
    //如果相交节点在环外,两个链表入环节点一定相同,简化为方法1
    if(n1==n2){
        int len1 = 0;
        int len2 = 0;
        Node cur2 = head2;
        while (cur1!=n1){
            cur1 = cur1.next;
            len1++;
        }
        while (cur2!=n2){
            cur2 = cur2.next;
            len2++;
        }
        cur1 = len1>len2?head1:head2;       //cur1指向较长的链表头节点
        cur2 = len1>len2?head2:head1;       //cur2指向较短的
        int len = Math.abs(len1-len2);
        while (len>0){
            cur1 = cur1.next;
            len--;
        }
        while (cur1!=cur2){
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }else {             //入环节点不相同:1.有交点  2.没有交点
        cur1 = n1;
        while (cur1!=n2){
            cur1 = cur1.next;
            if(cur1==n1) return null;       //n1继续走,在再次回到n1之前没有遇到n2说明没有交点
        }
        return n2;                         //  和n2相遇,返回n2

    }


}