【leetcode】環形連結串列及拓展
阿新 • • 發佈:2018-12-14
環形連結串列及拓展
一、要求
給定一個連結串列,判斷連結串列中是否有環。
進階: 你能否不使用額外空間解決此題?
節點類:
class ListNode {
public int val;
public ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
二、解法
(1)使用額外空間來判斷連結串列中是否有環
思路:遍歷整個連結串列,將每一次遍歷的節點存入Set中,利用Set存入相同元素返回false的特性,判斷連結串列中是否有環。
public boolean hasCycle(ListNode head) { Set<ListNode> set = new HashSet<>(); while (head != null) { boolean result = set.add(head); if (!result) { return true; } head = head.next; } return false; }
由於遍歷,導致時間複雜度為O(n),由於使用了Set集合,空間複雜度為O(n)。
(2)使用快慢指標。
思路:快慢指標都從頭節點開始,快指標一次走兩步,慢指標一次,如果慢指標能夠追趕上快指標,則證明連結串列中有環。
public boolean hasCylce2(ListNode head) { ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; //如果慢指標追趕上快指標的話,則說明有環 if (fast == slow) { return true; } } return false; }
三、拓展
拓展問題一:
如果連結串列有環,找出環的入口節點。
思路:快慢指標的相遇點到環入口的距離等於頭節點到環入口的距離,那麼在頭節點和相遇點各設一個相同步伐的指標,他們相遇的那個節點就是環入口。
public ListNode getEntrance(ListNode head) {
ListNode slow = head;
ListNode fast = head;
boolean isCycle = false;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
//如果慢指標追趕上快指標的話,則說明有環
if (fast == slow) {
isCycle = true;
break;
}
}
if (isCycle) {
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
return null;
}
拓展問題二:
若連結串列有環,求出環的長度。
思路:若連結串列有環,得到環入口,然後讓指標指向環入口,指標遍歷完重新回到環入口的路程即環的長度。
public int getCylceLength(ListNode head) {
int length = 0;
ListNode cycleNode = getEntrance(head);
if (cycleNode != null) {
ListNode temp = cycleNode;
while (true) {
temp = temp.next;
length++;
if (temp == cycleNode) {
break;
}
}
}
return length;
}