链表系列—链表环相关问题

1、链表环

1.1 判断单链表是否存在环

设置两个节点:slow、fast,若存在环,分别从链表的头节点出发,一个每次向后移动一步,另一个移动两步,两个指针移动速度不一样,如果存在环,那么两个指针一定会在环里相遇。

	 public boolean hasCircle(Node head) {
        if (head == null || head.next == null) {
            return false;
        }
        Node slow = head;
        Node fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }

1.2 带环单链表的入口节点

头结点和相遇结点时,将slow指向root,同步前进,则最后一定相遇在环入口结点。

	/**
     * 返回循环的入口节点:
     * <p>
     * slow:   a + b = n
     * fast:   a + b + kL = 2n
     * <p>
     * 相遇时:n = kL = a+b
     * <p>
     * slow 再走 n 步的话,还可以再回到相遇点,
     * fast 从头开始走的话,经过n步,也会达到相遇点M
     *
     * @return
     */
    public Node findLoopEnter(Node head) {
        if (head == null || head.next == null) {
            return null;
        }
        Node slow = head;
        Node fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                break;
            }
        }
        if (slow != fast) {
            return null;
        }
        fast = head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }

1.3 单链表环的长度

// 获取环的入口地址、循环一圈、每次加1
public int	circleLength(Node root){
		Node node=searchEntranceNode(root);
		if(node==null){
			return 0;
		}
		Node n=node.next;
		int length=1;
		while(n!=node){
			length++;
			n=n.next;
		}
		return length;
	}

1.4 两个无环链表交点

两个无环单链表是否相交,给出相交的第一个结点

  • 方法1
    将其中一个链表首尾相连,检测另外一个链表是否存在环;如果存在,则两个链表相交,而检测出来的环入口即为相交的第一个结点
  • 方法2
    如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点。我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。这时我们记下两个链表的长度,再遍历一次。长链表节点先出发前进(长链表长度-短链表长度)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点
/**
     * 无环链表相交的节点:
     * 方法1、先计算长度,在同步走比较
     * <p>
     * 方法2、递归或栈逆向对比
     *
     * @return
     */
    public Node findIntersectNode(Node head1, Node head2) {
       if (head1 == null || head2 ==  null){
           return null;
       }
       Stack<Node> stack1 = new Stack<>();
       Stack<Node> stack2 = new Stack<>();
       while (head1 != null){
           stack1.push(head1);
            head1 = head1.next;
       }
        while (head2 != null){
            stack2.push(head2);
            head2 = head2.next;
        }
       Node point = null;
       while (!stack1.isEmpty() && !stack2.isEmpty()){
           Node node1 = stack1.pop();
           Node node2 = stack2.pop();
           if (node1 == node2){
               point  = node1;
           }else {
               break;
           }
       }
       return point;
    }

两个有环链表是否相交

找到第一个链表的环点,然后将环断开(当然不要忘记了保存它的下一个节点),然后再来遍历第二个链表 ,如果发现 第二个链表从有环变成了无环,那么他们就是相交的嘛,否则就是不相交的了.
两个环相交必定存在公共的循环链部分,断开一个环另一个必定断开
注: 当一个链表中有环,一个链表中没有环时,两个链表必不相交

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值