问题:有一个单向链表,链表中可能会出现“环”,如何判断该链表是否有环呢?
1 从头节点开始,依次遍历单链表中的每一个节点。每遍历一个新节点,就从头检查新节点之前的所有节点,用新节点和此节点之前所有节点依次做比较。如果发现新节点和之前的某个节点相同,则说明该节点被遍历过两次,链表有环;如果之前的所有节点中不存在与新节点相同的节点,就继续遍历下一个新节点,继续重复刚才的操作。
假设链表节点为n,该解法的时间复杂度为O(n^2),并没有使用额外空间,所以空间复杂度为O(1)
2 先创建一个以节点id为Key的HashSet集合,用来存储曾经遍历过的节京。然后同样从头节点开始,依次遍历单链表中的每一个节点。每遍历一个新节点,都用新节点和HashSet集合中存储的节点进行比较,如果发现Hashset中存在与之相同的节点id,说明链表有环,如果Hashset中不存在与新节点相同的节点id,就把这个新节点id存入Hashset中,之后进入下一节点,继续重复刚才的操作
这个方法流程上和1类似,本质使用了hashSet作为额外的缓存,假设节点为n,时间复杂度为O(n),由于使用了额外的空间,所以空间复杂度是O(n)
3 在一个环行跑道上,两个运动员一个速度快,一个速度慢,跑了一段时间后,速度快的运动员总会追上速度慢的运动员,原因很简单,因为跑道是环形的
假设链表元素为n 时间复杂度为O(n),除了两个指针外,没有消耗额外空间,所以空间复杂度是O(1)
/**
* 判断链表是否有环
*
* @param head 链表头节点
* @return true
*/
public static boolean isCycle(Node head) {
Node p1 = head;
Node p2 = head;
while (p2 != null && p2.next != null) {
p1 = p1.next;
p2 = p2.next.next;
if (p1 == p2) {
return true;
}
}
return false;
}
/**
* 链表结构
*/
private static class Node {
int data;
Node next;
Node(int data) {
this.data = data;
}
}
@Test
public void test1() {
Node node1 = new Node(5);
Node node2 = new Node(3);
Node node3 = new Node(7);
Node node4 = new Node(2);
Node node5 = new Node(6);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node2;
System.out.println(isCycle(node1));
}