-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathhas_loop.js
More file actions
175 lines (148 loc) · 4.41 KB
/
has_loop.js
File metadata and controls
175 lines (148 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LL {
constructor() {
this.head = null;
this.tail = null;
this.count = 0;
}
add(value) {
let newNode = new Node(value);
if (this.count === 0) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
this.tail = newNode;
}
this.count++;
}
}
/**
* Detects if a linked list has a loop using hashing to store visited nodes.
* @param {Node} head - The head of the linked list.
* @returns {boolean} - True if a loop is detected, false otherwise.
*
* Time Complexity: O(n) - where n is the number of nodes in the linked list.
* Space Complexity: O(n) - in the worst case, hashmap stores information about all nodes.
*/
function hasLoopWithHashing(head) {
// Create a hashmap to store visited nodes
let hashmap = new Map();
let tempNode = head;
// Traverse the linked list
while (tempNode != null) {
// If the node is already in the hashmap, a loop is detected
if (hashmap.has(tempNode)) {
return true;
}
// Mark the current node as visited in the hashmap
hashmap.set(tempNode, true);
// Move to the next node
tempNode = tempNode.next;
}
// No loop found
return false;
}
/**
* Detects if a linked list has a loop using Floyd's Tortoise and Hare algorithm.
* @param {Node} head - The head of the linked list.
* @returns {boolean} - True if a loop is detected, false otherwise.
*
* Time Complexity: O(n) - where n is the number of nodes in the linked list.
* Space Complexity: O(1) - constant space, uses two pointers only.
*/
function hasLoopWithTwoPointers(head) {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
// No loop found
return false;
}
/**
* Finds the first node in the loop of a linked list using Floyd's Tortoise and Hare algorithm.
* @param {Node} head - The head of the linked list.
* @returns {Node|null} - The first node in the loop if a loop is detected, null otherwise.
*
* Time Complexity: O(n) - where n is the number of nodes in the linked list.
* Space Complexity: O(1) - constant space, uses two pointers only.
*/
function loopFirstNode(head) {
let slow = head;
let fast = head;
let loopExists = false;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
loopExists = true;
break;
}
}
if (loopExists) {
slow = head;
while (slow !== fast) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
// No loop found
return null;
}
/**
* Calculates the length of the loop in a linked list using Floyd's Tortoise and Hare algorithm.
* @param {Node} head - The head of the linked list.
* @returns {number} - The length of the loop if a loop is detected, 0 otherwise.
*
* Time Complexity: O(n) - where n is the number of nodes in the linked list.
* Space Complexity: O(1) - constant space, uses two pointers only.
*/
function loopLength(head) {
let slow = head;
let fast = head;
let loopExists = false;
let counter = 0;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
loopExists = true;
break;
}
}
if (loopExists) {
fast = fast.next;
counter = 1;
while (slow !== fast) {
fast = fast.next;
counter++;
}
return counter;
}
// No loop found
return 0;
}
// Create a linked list with a loop
let llWithLoop = new LL();
llWithLoop.add(1);
llWithLoop.add(2);
llWithLoop.add(3);
llWithLoop.add(4);
// Creating a loop by connecting the tail to the second node
llWithLoop.tail.next = llWithLoop.head.next;
// Test if the loop detection functions work
console.log(hasLoopWithHashing(llWithLoop.head)); // Expected output: true
console.log(hasLoopWithTwoPointers(llWithLoop.head)); // Expected output: true
console.log(loopFirstNode(llWithLoop.head)); // Expected output: Node with value 2
console.log(loopLength(llWithLoop.head)); // Expected output: 3