leetcode-142-环形链表 II-java

题目及测试

package pid142;
/*  142. 环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

https://leetcode-cn.com/problems/linked-list-cycle-ii/

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

 

进阶:
你是否可以不用额外空间解决此题?

*/
public class main {
	
public static void main(String[] args) {
		
		LinkList a=new LinkList(3);
		a.addLast(2);
		a.addLast(0);
		a.addLast(4);
		test(a.first);
		
		LinkList b=new LinkList(1);
		b.addLast(2);
		b.addLast(3);
		b.addLast(4);
		b.first.next.next.next.next = b.first.next;
		
		test(b.first);		
		
	}
		 
	private static void test(ListNode ito) {
		Solution solution = new Solution();
		ListNode rtn;
		long begin = System.currentTimeMillis();
		System.out.println();
		//开始时打印数组
		
		rtn=solution.detectCycle(ito);//执行程序
		long end = System.currentTimeMillis();	
		System.out.println("rtn=");
		
		System.out.println(":rtn" );
		if(rtn == null){
			System.out.println(rtn);
		}else{
			System.out.print(rtn.val);
		}		
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,1ms,较快)

使用双指针算法,一个slow指针,一个fast指针,一个每次1步,一个每次两步,链表如果循环,分为开始的不循环部分not和循环的circle,slow走了x的距离,fast走了2x的距离,slow与fast相遇时,fast比slow多走了circle的距离,x+circle=2x,所以slow走的距离就是circle。

然后两个指针都到head,fast先走circle步,然后fast和slow每次都走一步,如果slow走了not距离,fast则总共走了now+circle距离,完成一次大循环,重新来到刚开始循环的地方,返回这个节点即可。

注意:当not远大于circle时,第一步算出来的circle会是真是circle的k倍,但是不影响第二步,一个走了not,一个走了now+k*circle,下一步还是刚开始循环的地方

package pid142;


/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
    	if(head==null || head.next == null){
    		return null;
    	}
        ListNode fast = head;
        ListNode slow = head;
        int span = 0;
        while(true){
        	if(fast.next==null){
        		return null;
        	}
        	fast = fast.next;
        	if(fast.next==null){
        		return null;
        	}
        	fast = fast.next;
        	slow = slow.next;
        	span++;
        	if(fast == slow){
        		break;
        	}
        }
        fast = head;
        slow = head;
        for(int i=0;i

 

解法2(别人的)

首先,我们分配一个 Set 去保存所有的列表节点。我们逐一遍历列表,检查当前节点是否出现过,如果节点已经出现过,那么一定形成了环且它是环的入口。否则如果有其他点是环的入口,我们应该先访问到其他节点而不是这个节点。其他情况,没有成环则直接返回 null 。

算法会在遍历有限个节点后终止,这是因为输入列表会被分成两类:成环的和不成环的。一个不成欢的列表在遍历完所有节点后会到达 null - 即链表的最后一个元素后停止。一个成环列表可以想象成是一个不成环列表将最后一个 null 元素换成环的入口。

如果 while 循环终止,我们返回 null 因为我们已经将所有的节点遍历了一遍且没有遇到重复的节点,这种情况下,列表是不成环的。对于循环列表, while 循环永远不会停止,但在某个节点上, if 条件会被满足并导致函数的退出。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        Set visited = new HashSet();

        ListNode node = head;
        while (node != null) {
            if (visited.contains(node)) {
                return node;
            }
            visited.add(node);
            node = node.next;
        }

        return null;
    }
}

解法3(别人的)

对解法1的优化,可以发现解法1内,第一步相遇时,slow走了circle的距离,恰好是第二步里fast要先走的距离。

就是第一步里相遇的地方,就是第二步里fast先走完后的位置,只需slow节点指向head,然后两个指针一起走即可

该方法为弗洛伊德算法,具体见  https://leetcode-cn.com/problems/linked-list-cycle-ii/solution/huan-xing-lian-biao-ii-by-leetcode/

public class Solution {
    private ListNode getIntersect(ListNode head) {
        ListNode tortoise = head;
        ListNode hare = head;

        // A fast pointer will either loop around a cycle and meet the slow
        // pointer or reach the `null` at the end of a non-cyclic list.
        while (hare != null && hare.next != null) {
            tortoise = tortoise.next;
            hare = hare.next.next;
            if (tortoise == hare) {
                return tortoise;
            }
        }

        return null;
}

    public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }

        // If there is a cycle, the fast/slow pointers will intersect at some
        // node. Otherwise, there is no cycle, so we cannot find an e***ance to
        // a cycle.
        ListNode intersect = getIntersect(head);
        if (intersect == null) {
            return null;
        }

        // To find the e***ance to the cycle, we have two pointers traverse at
        // the same speed -- one from the front of the list, and the other from
        // the point of intersection.
        ListNode ptr1 = head;
        ListNode ptr2 = intersect;
        while (ptr1 != ptr2) {
            ptr1 = ptr1.next;
            ptr2 = ptr2.next;
        }

        return ptr1;
    }
}

你可能感兴趣的:(leetcode,leetcode-中等,数据结构-链表)