Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 491f01a

Browse files
authoredSep 19, 2022
refactor: js | linkedlist (#770)
1 parent 23b6d27 commit 491f01a

12 files changed

+732
-359
lines changed
 
Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,65 @@
11
/**
2+
* https://leetcode.com/problems/copy-list-with-random-pointer/
3+
* Time O(N) | Space O(N)
24
* @param {Node} head
35
* @return {Node}
46
*/
5-
var copyRandomList = function (head) {
6-
let map = new Map();
7-
let ptr = head;
8-
9-
while (ptr) {
10-
// map old - new
11-
map.set(ptr, new Node(ptr.val, null, null));
12-
ptr = ptr.next;
7+
var copyRandomList = function(head, map = new Map()) {
8+
if (!head) return null;
9+
if (map.has(head)) return map.get(head);
10+
11+
const clone = new Node(head.val);
12+
13+
map.set(head, clone); /* | Space O(N) */
14+
clone.next = copyRandomList(head.next, map); /* Time O(N) | Space O(N) */
15+
clone.random = copyRandomList(head.random, map);/* Time O(N) | Space O(N) */
16+
17+
return clone;
18+
}
19+
20+
/**
21+
* https://leetcode.com/problems/copy-list-with-random-pointer/
22+
* Time O(N) | Space O(1)
23+
* @param {Node} head
24+
* @return {Node}
25+
*/
26+
var copyRandomList = function(head) {
27+
if (!head) return null;
28+
29+
cloneNode(head); /* Time O(N) */
30+
connectRandomNode(head); /* Time O(N) */
31+
32+
return connectNode(head);/* Time O(N) */
33+
};
34+
35+
const cloneNode = (curr) => {
36+
while (curr) { /* Time O(N) */
37+
const node = new Node(curr.val);
38+
39+
node.next = curr.next;
40+
curr.next = node;
41+
curr = node.next;
1342
}
1443

15-
for (const [oldptr, newptr] of map) {
16-
newptr.next = oldptr.next && map.get(oldptr.next);
17-
newptr.random = oldptr.random && map.get(oldptr.random);
44+
return curr;
45+
}
46+
47+
const connectRandomNode = (curr) => {
48+
while (curr) { /* Time O(N) */
49+
curr.next.random = curr.random?.next || null;
50+
curr = curr.next.next;
1851
}
19-
return map.get(head);
20-
};
52+
}
53+
54+
const connectNode = (head) => {
55+
let [ prev, curr, next ] = [ head, head.next, head.next ];
56+
57+
while (prev) { /* Time O(N) */
58+
prev.next = prev.next.next;
59+
curr.next = curr?.next?.next || null;
60+
prev = prev.next;
61+
curr = curr.next;
62+
}
63+
64+
return next
65+
}

‎javascript/141-Linked-List-Cycle.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
/**
2-
* Definition for singly-linked list.
3-
* function ListNode(val) {
4-
* this.val = val;
5-
* this.next = null;
6-
* }
2+
* https://leetcode.com/problems/linked-list-cycle/
3+
* Time O(N) | Space O(N)
4+
* @param {ListNode} head
5+
* @return {boolean}
76
*/
7+
var hasCycle = function(head, seen = new Set()) {
8+
while (head) {/* Time O(N) */
9+
if (seen.has(head)) return true;
10+
11+
seen.add(head);/* Space O(N) */
12+
head = head.next;
13+
}
14+
15+
return false;
16+
}
817

918
/**
19+
* https://leetcode.com/problems/linked-list-cycle/
20+
* Time O(N) | Space O(1)
1021
* @param {ListNode} head
1122
* @return {boolean}
1223
*/
13-
var hasCycle = function (head) {
14-
let set = new Set();
15-
while (head) {
16-
if (set.has(head)) {
17-
return true;
18-
} else {
19-
set.add(head);
20-
head = head.next;
21-
}
24+
var hasCycle = function(head) {
25+
let [ slow, fast ] = [ head, head];
26+
27+
while (fast && fast.next) {/* Time O(N) */
28+
slow = slow.next;
29+
fast = fast.next.next;
30+
31+
const hasCycle = slow === fast;
32+
if (hasCycle) return true;
2233
}
2334

2435
return false;
25-
};
36+
};

‎javascript/143-Reorder-List.js

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,51 @@
11
/**
2-
* Definition for singly-linked list.
3-
* function ListNode(val, next) {
4-
* this.val = (val===undefined ? 0 : val)
5-
* this.next = (next===undefined ? null : next)
6-
* }
7-
*/
8-
/**
2+
* https://leetcode.com/problems/reorder-list/
3+
* Time O(N) | Space O(1)
94
* @param {ListNode} head
105
* @return {void} Do not return anything, modify head in-place instead.
116
*/
12-
var reorderList = function (head) {
13-
if (!head) {
14-
return;
15-
}
7+
var reorderList = function(head) {
8+
const mid = getMid(head); /* Time O(N) */
9+
const reveredFromMid = reverse(mid);/* Time O(N) */
1610

17-
let slow = head;
18-
let fast = head;
11+
reorder(head, reveredFromMid); /* Time O(N) */
12+
};
13+
14+
const getMid = (head) => {
15+
let [ slow, fast ] = [ head, head ];
1916

20-
// finding the middle of the linked list using 2 pters
21-
while (fast && fast.next) {
17+
while (fast && fast.next) { /* Time O(N) */
2218
slow = slow.next;
2319
fast = fast.next.next;
2420
}
2521

26-
// reverse the second part of the list starting at slow
27-
let prev = null;
28-
let curr = slow;
29-
while (curr) {
30-
let next = curr.next;
22+
return slow;
23+
}
24+
25+
const reverse = (head) => {
26+
let [ prev, curr, next ] = [ null, head, null ];
27+
28+
while (curr) { /* Time O(N) */
29+
next = curr.next;
3130
curr.next = prev;
31+
3232
prev = curr;
3333
curr = next;
34-
} // here prev is the head
34+
}
3535

36-
// merge two sorted lists (first one starts at head, second at prev)
37-
let first = head;
38-
let second = prev;
36+
return prev;
37+
}
3938

40-
while (second.next) {
41-
temp = first.next;
39+
const reorder = (l1, l2) => {
40+
let [ first, next, second ] = [ l1, null, l2 ];
41+
42+
while (second.next) { /* Time O(N) */
43+
next = first.next;
4244
first.next = second;
43-
first = temp;
45+
first = next;
4446

45-
temp = second.next;
47+
next = second.next;
4648
second.next = first;
47-
second = temp;
49+
second = next;
4850
}
49-
};
51+
}

‎javascript/146-LRU-Cache.js

Lines changed: 50 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,70 @@
1-
//////////////////////////////////////////////////////////////////////////////
2-
// JavaScript Map Class Implementation
3-
// This solution produces a lot less code, but is exposed to poor performance
4-
// due to Map's internal maintenance of the order of properties. Constantly
5-
// deleting and resetting properties upon each retrieval is costly.
6-
//////////////////////////////////////////////////////////////////////////////
7-
8-
/**
9-
* @param {number} capacity
1+
/**
2+
* https://leetcode.com/problems/lru-cache/
3+
* Time O(1) | Space O(N)
4+
* Your LRUCache object will be instantiated and called as such:
5+
* var obj = new LRUCache(capacity)
6+
* var param_1 = obj.get(key)
7+
* obj.put(key,value)
108
*/
11-
function LRUCache(capacity) {
12-
this.capacity = capacity;
13-
this.cacheMap = new Map();
14-
}
9+
class LRUCache {
10+
constructor(capacity) {
11+
this.capacity = capacity;
12+
this.map = new Map();
1513

16-
/**
17-
* @param {number} key
18-
* @return {number}
19-
*/
20-
LRUCache.prototype.get = function (key) {
21-
if (!this.cacheMap.has(key)) {
22-
return -1;
23-
}
24-
const value = this.cacheMap.get(key);
25-
this.cacheMap.delete(key);
26-
this.cacheMap.set(key, value);
27-
return value;
28-
};
14+
this.head = {};
15+
this.tail = {};
2916

30-
/**
31-
* @param {number} key
32-
* @param {number} value
33-
* @return {void}
34-
*/
35-
LRUCache.prototype.put = function (key, value) {
36-
if (this.cacheMap.has(key)) {
37-
this.cacheMap.delete(key);
38-
} else if (this.cacheMap.size === this.capacity) {
39-
const leastRecentlyUsedKey = this.cacheMap.keys().next().value;
40-
this.cacheMap.delete(leastRecentlyUsedKey);
17+
this.head.next = this.tail;
18+
this.tail.prev = this.head;
4119
}
42-
this.cacheMap.set(key, value);
43-
};
4420

45-
//////////////////////////////////////////////////////////////////////////////
46-
// JavaScript Object Class Implementation
47-
// This solution requires more code and space due to the need to separately
48-
// define a doubly linked list and a hash map, but has better performance due
49-
// to strictly maintaining constant time lookups and additions.
50-
//////////////////////////////////////////////////////////////////////////////
21+
removeLastUsed () {
22+
const [ key, next, prev ] = [ this.head.next.key, this.head.next.next, this.head ];
5123

52-
class LRUNode {
53-
/**
54-
* @param {number} key
55-
* @param {number} val
56-
* @param {LRUNode=} next = `null`
57-
* @constructor
58-
*/
59-
constructor(key, val, next = null) {
60-
this.key = key;
61-
this.val = val;
62-
this.prev = null;
63-
this.next = next;
24+
this.map.delete(key);
25+
this.head.next = next;
26+
this.head.next.prev = prev;
6427
}
65-
}
6628

67-
class LRUCache {
68-
/**
69-
* @param {number} capacity
70-
* @constructor
71-
*/
72-
constructor(capacity) {
73-
this.head = null;
74-
this.tail = null;
75-
this.map = Object.create(null);
76-
this.length = 0;
77-
this.capacity = capacity;
78-
}
29+
put (key, value) {
30+
const hasKey = this.get(key) !== -1;
31+
const isAtCapacity = this.map.size === this.capacity;
32+
33+
if (hasKey) return (this.tail.prev.value = value);
34+
if (isAtCapacity) this.removeLastUsed();
7935

80-
/**
81-
* @param {number} key
82-
* @return {number}
83-
*/
84-
get(key) {
85-
if (!(key in this.map)) {
86-
return -1;
87-
}
88-
this.makeMostRecent(key);
89-
return this.map[key].val;
36+
const node = { key, value };
37+
this.map.set(key, node);
38+
this.moveToFront(node);
9039
}
9140

92-
/**
93-
* @param {number} key
94-
* @param {number} val
95-
* @return {void}
96-
*/
97-
put(key, val) {
98-
if (key in this.map) {
99-
this.map[key].val = val;
100-
this.makeMostRecent(key);
101-
return;
102-
}
103-
104-
if (this.length === this.capacity) {
105-
delete this.map[this.tail.key];
106-
if (this.head === this.tail) {
107-
this.head = null;
108-
this.tail = null;
109-
} else {
110-
this.tail = this.tail.prev;
111-
this.tail.next = null;
112-
}
113-
} else {
114-
++this.length;
115-
}
41+
moveToFront (node) {
42+
const [ prev, next ] = [ this.tail.prev, this.tail ];
11643

117-
const node = new LRUNode(key, val, this.head);
118-
119-
if (this.head) {
120-
this.head.prev = node;
121-
} else {
122-
this.tail = node;
123-
}
124-
this.head = node;
44+
this.tail.prev.next = node;
45+
this.connectNode(node, { prev, next });
46+
this.tail.prev = node;
47+
}
12548

126-
this.map[key] = node;
49+
connectNode (node, top) {
50+
node.prev = top.prev;
51+
node.next = top.next;
12752
}
12853

129-
/**
130-
* @param {number} key
131-
* @return {void}
132-
*/
133-
makeMostRecent(key) {
134-
const node = this.map[key];
54+
get (key) {
55+
const hasKey = this.map.has(key);
56+
if (!hasKey) return -1;
13557

136-
if (node === this.head) {
137-
return node.val;
138-
}
58+
const node = this.map.get(key);
59+
60+
this.disconnectNode(node);
61+
this.moveToFront(node);
13962

140-
if (node.prev) {
141-
node.prev.next = node.next;
142-
}
143-
if (node.next) {
144-
node.next.prev = node.prev;
145-
}
146-
if (node === this.tail) {
147-
this.tail = node.prev;
148-
}
63+
return node.value;
64+
}
14965

150-
node.prev = null;
151-
node.next = this.head;
152-
this.head.prev = node;
153-
this.head = node;
66+
disconnectNode (node) {
67+
node.next.prev = node.prev;
68+
node.prev.next = node.next;
15469
}
15570
}
Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,74 @@
11
/**
2-
* Definition for singly-linked list.
3-
* function ListNode(val, next) {
4-
* this.val = (val===undefined ? 0 : val)
5-
* this.next = (next===undefined ? null : next)
6-
* }
7-
*/
8-
/**
2+
* https://leetcode.com/problems/merge-two-sorted-lists/
3+
* Time O(N) | Space O(N)
94
* @param {ListNode} head
105
* @param {number} n
116
* @return {ListNode}
127
*/
13-
var removeNthFromEnd = function (head, n) {
14-
let currNode = head;
15-
let nodeBeforeN = head;
8+
var removeNthFromEnd = function(head, n) {
9+
const sentinel = new ListNode();
1610

17-
for (let i = 0; i < n; i++) {
18-
currNode = currNode.next;
19-
}
11+
sentinel.next = head;
12+
13+
const fast = moveFast(sentinel, n); /* Time O(N) */
14+
const slow = moveSlow(sentinel, fast);/* Time O(N) */
15+
16+
slow.next = slow.next.next || null;
17+
18+
return sentinel.next;
19+
};
2020

21-
if (!currNode) {
22-
return head.next;
21+
const moveFast = (fast, n) => {
22+
for (let i = 1; i <= (n + 1); i++) {/* Time O(N) */
23+
fast = fast.next;
2324
}
2425

25-
while (currNode.next) {
26-
nodeBeforeN = nodeBeforeN.next;
27-
currNode = currNode.next;
26+
return fast;
27+
}
28+
29+
const moveSlow = (slow, fast) => {
30+
while (fast) { /* Time O(N) */
31+
slow = slow.next;
32+
fast = fast.next;
2833
}
2934

30-
nodeBeforeN.next = nodeBeforeN.next.next;
35+
return slow;
36+
}
3137

32-
return head;
38+
/**
39+
* https://leetcode.com/problems/merge-two-sorted-lists/
40+
* Time O(N) | Space O(1)
41+
* @param {ListNode} head
42+
* @param {number} n
43+
* @return {ListNode}
44+
*/
45+
var removeNthFromEnd = function(head, n) {
46+
const length = getNthFromEnd(head, n);/* Time O(N) */
47+
48+
const isHead = length < 0;
49+
if (isHead) return head.next;
50+
51+
const curr = moveNode(head, length); /* Time O(N) */
52+
53+
curr.next = curr.next.next;
54+
55+
return head
3356
};
57+
58+
const getNthFromEnd = (curr, n, length = 0) => {
59+
while (curr) { /* Time O(N) */
60+
curr = curr.next;
61+
length++;
62+
}
63+
64+
return (length - n) - 1;
65+
}
66+
67+
const moveNode = (curr, length) => {
68+
while (length) { /* Time O(N) */
69+
curr = curr.next;
70+
length--;
71+
}
72+
73+
return curr;
74+
}

‎javascript/2-Add-Two-Numbers.js

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,60 @@
1-
function addTwoNumbers(l1, l2) {
2-
let temp1 = l1;
3-
let temp2 = l2;
1+
/**
2+
* https://leetcode.com/problems/add-two-numbers/
3+
* Time O(MAX(N, M)) | Space O(MAX(N, M))
4+
* @param {ListNode} l1
5+
* @param {ListNode} l2
6+
* @return {ListNode}
7+
*/
8+
var addTwoNumbers = function(l1, l2) {
9+
let sentinel = tail = new ListNode();
410

5-
let dummy = new ListNode(0);
6-
let merged = dummy;
11+
return add(l1, l2, tail, sentinel); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */
12+
}
713

8-
let carry = 0;
14+
const add = (l1, l2, tail, sentinel, carry = 0) => {
15+
const isBaseCase = !(l1 || l2 || carry);
16+
if (isBaseCase) return sentinel.next;
917

10-
while (temp1 || temp2) {
11-
let sum = (temp1?.val || 0) + (temp2?.val || 0) + carry;
12-
carry = Math.floor(sum / 10);
13-
sum = sum % 10;
18+
return dfs(l1, l2, tail, sentinel, carry);/* Time O(MAX(N, M)) | Space O(MAX(N, M)) */
19+
}
1420

15-
merged.next = new ListNode(sum);
16-
merged = merged.next;
21+
const dfs = (l1, l2, tail, sentinel, carry) => {
22+
const sum = (l1?.val || 0) + (l2?.val || 0) + carry;
23+
const val = sum % 10;
24+
carry = Math.floor(sum / 10);
1725

18-
if (temp1) temp1 = temp1?.next;
19-
if (temp2) temp2 = temp2?.next;
20-
}
26+
tail.next = new ListNode(val);
27+
tail = tail.next;
2128

22-
if (carry > 0) {
23-
merged.next = new ListNode(carry);
24-
}
29+
l1 = l1?.next || null;
30+
l2 = l2?.next || null;
31+
32+
add(l1, l2, tail, sentinel, carry); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */
2533

26-
return dummy.next;
34+
return sentinel.next;
2735
}
36+
37+
/**
38+
* https://leetcode.com/problems/add-two-numbers/
39+
* Time O(MAX(N, M)) | Space O(MAX(N, M))
40+
* @param {ListNode} l1
41+
* @param {ListNode} l2
42+
* @return {ListNode}
43+
*/
44+
var addTwoNumbers = function(l1, l2, carry = 0) {
45+
let sentinel = tail = new ListNode();
46+
47+
while (l1 || l2 || carry) {/* Time O(MAX(N, M)) */
48+
const sum = (l1?.val || 0) + (l2?.val || 0) + carry;
49+
const val = sum % 10;
50+
carry = Math.floor(sum / 10);
51+
52+
tail.next = new ListNode(val);
53+
tail = tail.next;
54+
55+
l1 = l1?.next || null;
56+
l2 = l2?.next || null;
57+
}
58+
59+
return sentinel.next;
60+
};

‎javascript/206-Reverse-Linked-List.js

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
/**
2-
* Definition for singly-linked list.
3-
* function ListNode(val, next) {
4-
* this.val = (val===undefined ? 0 : val)
5-
* this.next = (next===undefined ? null : next)
6-
* }
2+
* https://leetcode.com/problems/reverse-linked-list/
3+
* Time O(N) | Space O(N)
4+
* @param {ListNode} head
5+
* @return {ListNode}
76
*/
7+
var reverseList = function (head) {
8+
const isBaseCase = !head?.next;
9+
if (isBaseCase) return head;
10+
11+
return dfs(head); /* Time O(N) | Space O(N) */
12+
}
13+
14+
const dfs = (curr) => {
15+
const prev = reverseList(curr.next);/* Time O(N) | Space O(N) */
16+
17+
curr.next.next = curr;
18+
curr.next = null;
19+
20+
return prev;
21+
}
22+
823
/**
24+
* https://leetcode.com/problems/reverse-linked-list/
25+
* Time O(N) | Space O(1)
926
* @param {ListNode} head
1027
* @return {ListNode}
1128
*/
12-
var reverseList = function (head) {
13-
let prev = null;
29+
var reverseList = function (head) {
30+
let [ prev, curr, next ] = [ null, head, null ];
31+
32+
while (curr) {/* Time O(N) */
33+
next = curr.next;
34+
curr.next = prev;
1435

15-
while (head) {
16-
let next = head.next;
17-
head.next = prev;
18-
prev = head;
19-
head = next;
36+
prev = curr;
37+
curr = next;
2038
}
2139

2240
return prev;
23-
};
41+
};
Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,60 @@
11
/**
2-
* Definition for singly-linked list.
3-
* function ListNode(val, next) {
4-
* this.val = (val===undefined ? 0 : val)
5-
* this.next = (next===undefined ? null : next)
6-
* }
2+
* https://leetcode.com/problems/merge-two-sorted-lists/
3+
* Time O(N + M) | Space O(N + M)
4+
* @param {ListNode} list1
5+
* @param {ListNode} list2
6+
* @return {ListNode}
77
*/
8+
var mergeTwoLists = function(list1, list2) {
9+
const isBaseCase1 = list1 === null;
10+
if (isBaseCase1) return list2;
11+
12+
const isBaseCase2 = list2 === null;
13+
if (isBaseCase2) return list1;
14+
15+
const isL2Greater = list1.val <= list2.val;
16+
if (isL2Greater) {
17+
list1.next = mergeTwoLists(list1.next, list2);/* Time O(N + M) | Space O(N + M) */
18+
19+
return list1;
20+
}
21+
22+
const isL2Less = list2.val <= list1.val;
23+
if (isL2Less) {
24+
list2.next = mergeTwoLists(list1, list2.next);/* Time O(N + M) | Space O(N + M) */
25+
26+
return list2;
27+
}
28+
}
29+
830
/**
31+
* https://leetcode.com/problems/merge-two-sorted-lists/
32+
* Time O(N + M) | Space O(N + M)
933
* @param {ListNode} list1
1034
* @param {ListNode} list2
1135
* @return {ListNode}
1236
*/
13-
var mergeTwoLists = function (l1, l2) {
14-
let nullNode = { val: 0, next: null };
15-
let prev = nullNode;
16-
while (l1 && l2) {
17-
if (l1.val >= l2.val) {
18-
prev.next = l2;
19-
l2 = l2.next;
20-
} else {
21-
prev.next = l1;
22-
l1 = l1.next;
37+
var mergeTwoLists = function(list1, list2) {
38+
let sentinel = tail = new ListNode();
39+
40+
while (list1 && list2) {/* Time O(N + M) */
41+
const isL2Greater = list1.val <= list2.val;
42+
const isL2Less = list2.val < list1.val;
43+
44+
if (isL2Greater) {
45+
tail.next = list1;
46+
list1 = list1.next;
47+
}
48+
49+
if (isL2Less) {
50+
tail.next = list2;
51+
list2 = list2.next;
2352
}
24-
prev = prev.next;
53+
54+
tail = tail.next;
2555
}
26-
prev.next = l1 || l2;
27-
return nullNode.next;
28-
};
56+
57+
tail.next = list1 || list2;
58+
59+
return sentinel.next;
60+
};

‎javascript/23-Merge-K-Sorted-Lists.js

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,78 @@
1-
var merge = function (l1, l2) {
2-
let tempNode = new ListNode(0);
3-
let current = tempNode;
4-
5-
while (l1 && l2) {
6-
if (l1.val < l2.val) {
7-
current.next = l1;
8-
l1 = l1.next;
1+
/**
2+
* https://leetcode.com/problems/merge-k-sorted-lists/
3+
* Time O(N) | Space O(N)
4+
* @param {ListNode[]} lists
5+
* @return {ListNode}
6+
*/
7+
var mergeKLists = function(lists) {
8+
let previous = null;
9+
10+
for (let i = 0; i < lists.length; i++) {
11+
previous = mergeTwoLists(previous, lists[i]);
12+
}
13+
14+
return previous;
15+
};
16+
17+
var mergeTwoLists = function(list1, list2) {
18+
let sentinel = tail = new ListNode(0);
19+
20+
while (list1 && list2) {
21+
const canAddL1 = list1.val <= list2.val;
22+
if (canAddL1) {
23+
tail.next = list1;
24+
list1 = list1.next;
925
} else {
10-
current.next = l2;
11-
l2 = l2.next;
26+
tail.next = list2;
27+
list2 = list2.next;
1228
}
13-
current = current.next;
29+
30+
tail = tail.next;
1431
}
15-
if (l1) current.next = l1;
16-
if (l2) current.next = l2;
1732

18-
return tempNode.next;
33+
tail.next = list1 || list2;
34+
35+
return sentinel.next;
1936
};
2037

21-
var mergeKLists = function (lists) {
22-
let root = lists[0];
38+
/**
39+
* https://leetcode.com/problems/merge-k-sorted-lists/
40+
* Time O(N * log(K)) | Space O(N + K)
41+
* @param {ListNode[]} lists
42+
* @return {ListNode}
43+
*/
44+
var mergeKLists = function(lists) {
45+
const minHeap = getMinHeap(lists);
2346

24-
for (let i = 1; i < lists.length; i++) {
25-
root = merge(root, lists[i]);
26-
}
27-
return root || null;
47+
return mergeLists(minHeap)
2848
};
49+
50+
const getMinHeap = (lists) => {
51+
const heap = new MinPriorityQueue({ priority: ({ val }) => val });
52+
53+
for (const node of lists) {
54+
if (!node) continue;
55+
56+
heap.enqueue(node);
57+
}
58+
59+
return heap;
60+
}
61+
62+
63+
const mergeLists = (minHeap) => {
64+
let sentinel = tail = new ListNode();
65+
66+
while (!minHeap.isEmpty()) {
67+
const node = minHeap.dequeue().element;
68+
69+
tail.next = node;
70+
tail = tail.next;
71+
72+
if (!node.next) continue;
73+
74+
minHeap.enqueue(node.next);
75+
}
76+
77+
return sentinel.next;
78+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* https://leetcode.com/problems/reverse-nodes-in-k-group/
3+
* Time O(N) | Space O(N)
4+
* @param {ListNode} head
5+
* @param {number} k
6+
* @return {ListNode}
7+
*/
8+
var reverseKGroup = function(head, k) {
9+
const sentinel = tail = new ListNode(0, head);
10+
11+
while (true) {
12+
let [ start, last ]= moveNode(tail, k);
13+
if (!last) break;
14+
15+
reverse([ start, tail.next, start ])
16+
17+
const next = tail.next;
18+
tail.next = last;
19+
tail = next;
20+
}
21+
22+
return sentinel.next;
23+
};
24+
25+
const moveNode = (curr, k) => {
26+
const canMove = () => k && curr;
27+
while (canMove()) {
28+
curr = curr.next;
29+
k--;
30+
}
31+
32+
return [ (curr?.next || null), curr ];
33+
}
34+
35+
const reverse = ([ prev, curr, start ]) => {
36+
const isSame = () => curr === start;
37+
while (!isSame()) {
38+
const next = curr.next;
39+
curr.next = prev;
40+
41+
prev = curr;
42+
curr = next;
43+
}
44+
}

‎javascript/25-Reverse-Nodes-in-K-Group.js

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 257 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,257 @@
1-
function findDuplicate(nums) {
2-
let slow = 0;
3-
let fast = 0;
4-
5-
while (true) {
6-
slow = nums[slow];
7-
fast = nums[nums[fast]];
8-
if (slow == fast) {
9-
break;
10-
}
11-
}
12-
13-
let slow2 = 0;
14-
15-
while (true) {
16-
slow = nums[slow];
17-
slow2 = nums[slow2];
18-
if (slow == slow2) {
19-
break;
20-
}
21-
}
22-
23-
return slow;
24-
}
1+
/**
2+
* https://leetcode.com/problems/find-the-duplicate-number/
3+
* Time O(N * log(N)) | Space O(1)
4+
* @param {number[]} nums
5+
* @return {number}
6+
*/
7+
var findDuplicate = function(nums) {
8+
nums.sort((a, b) => a - b);/* Time O(N * log(N)) | HeapSort Space O(1) | QuickSort Space O(log(N)) */
9+
10+
for (let i = 1; i < nums.length; i++) {/* Time O(N) */
11+
const isPrevDuplicate = nums[i - 1] === nums[i]
12+
if (isPrevDuplicate) return nums[i];
13+
}
14+
15+
return -1;
16+
}
17+
18+
/**
19+
* https://leetcode.com/problems/find-the-duplicate-number/
20+
* Time O(N * log(N)) | Space O(1)
21+
* @param {number[]} nums
22+
* @return {number}
23+
*/
24+
var findDuplicate = function(nums) {
25+
let [ left, right, duplicate ] = [ 1, (nums.length - 1), -1 ];
26+
27+
while (left <= right) {/* Time O(log(N)) */
28+
const mid = (left + right) >> 1;
29+
const count = getCount(mid, nums);/* Time O(N) */
30+
31+
const isMidGreater = count <= mid
32+
if (isMidGreater) left = mid + 1;
33+
34+
const isMidLess = mid < count
35+
if (isMidLess) {
36+
duplicate = mid;
37+
right = mid - 1;
38+
}
39+
}
40+
41+
return duplicate;
42+
}
43+
44+
const getCount = (mid, nums, count = 0) => {
45+
for (const num of nums) {/* Time O(N) */
46+
const isMidGreater = num <= mid
47+
if (isMidGreater) count++;
48+
}
49+
50+
return count;
51+
}
52+
53+
/**
54+
* https://leetcode.com/problems/find-the-duplicate-number/
55+
* Time O(N * log(N)) | Space O(1)
56+
* @param {number[]} nums
57+
* @return {number}
58+
*/
59+
var findDuplicate = function(nums, duplicate = 0) {
60+
const mostSignificantBit = calcMaxBit(nums); /* Time O(N) */
61+
62+
for (let bit = 0; bit < mostSignificantBit; bit++) {/* Time O(log(N)) */
63+
const [ baseCount, numsCount, mask ] = count(nums, bit);/* Time O(N) */
64+
65+
const isMoreFrequentlySet = baseCount < numsCount
66+
if (isMoreFrequentlySet) duplicate |= mask;
67+
}
68+
69+
return duplicate;
70+
}
71+
72+
const calcMaxBit = (nums, bits = 0) => {
73+
let max = Math.max(0, ...nums);/* Time O(N) */
74+
75+
while (max) {/* Time O(log(MAX)) */
76+
max >>= 1;
77+
bits++;
78+
}
79+
80+
return bits;
81+
}
82+
83+
const count = (nums, bit) => {
84+
let [ baseCount, numsCount, mask ] = [ 0, 0, (1 << bit) ];
85+
86+
for (let i = 0; i < nums.length; i++) {/* Time O(N) */
87+
const isBaseBitSet = 0 < (i & mask);
88+
if (isBaseBitSet) baseCount++;
89+
90+
const isNumBitSet = 0 < (nums[i] & mask);
91+
if (isNumBitSet) numsCount++;
92+
}
93+
94+
return [ baseCount, numsCount, mask ];
95+
}
96+
97+
/**
98+
* https://leetcode.com/problems/find-the-duplicate-number/
99+
* Time O(N) | Space O(N)
100+
* @param {number[]} nums
101+
* @return {number}
102+
*/
103+
var findDuplicate = function(nums, curr = 0) {
104+
const isBaseCase = curr === nums[curr]
105+
if (isBaseCase) return curr;
106+
107+
const next = nums[curr];
108+
109+
nums[curr] = curr;
110+
111+
return findDuplicate(nums, next);/* Time O(N) | Space O(N) */
112+
}
113+
114+
/**
115+
* https://leetcode.com/problems/find-the-duplicate-number/
116+
* Time O(N) | Space O(N)
117+
* @param {number[]} nums
118+
* @return {number}
119+
*/
120+
var findDuplicate = function(nums, seen = new Set()) {
121+
for (const num of nums) {/* Time O(N) */
122+
if (seen.has(num)) return num;
123+
124+
seen.add(num); /* Space O(N) */
125+
}
126+
127+
return -1;
128+
}
129+
130+
/**
131+
* https://leetcode.com/problems/find-the-duplicate-number/
132+
* Time O(N) | Space O(1)
133+
* @param {number[]} nums
134+
* @return {number}
135+
*/
136+
var findDuplicate = function(nums) {
137+
cyclicSort(nums); /* Time O(N) */
138+
139+
return search(nums); /* Time O(N) */
140+
}
141+
142+
const cyclicSort = (nums, index = 0) => {
143+
const swap = (arr, a, b) => [arr[a], arr[b]] = [arr[b], arr[a]];
144+
145+
while (index < nums.length) { /* Time O(N) */
146+
const [ num, arrayIndex, arrayNum ] = [ nums[index], (nums[index] - 1), nums[(nums[index] - 1)] ];
147+
148+
const canSwap = !isSame(num, arrayNum);
149+
if (canSwap) {
150+
swap(nums, index, arrayIndex);
151+
152+
continue;
153+
}
154+
155+
index++;
156+
}
157+
}
158+
const isSame = (a, b) => a === b;
159+
160+
const search = (nums) => {
161+
for (let index = 0; index < nums.length; index++) {/* Time O(N) */
162+
const [ num, arrayIndex ] = [ nums[index], (index + 1) ];
163+
164+
if (!isSame(num, arrayIndex)) return num;
165+
}
166+
167+
return nums.length;
168+
}
169+
170+
/**
171+
* https://leetcode.com/problems/find-the-duplicate-number/
172+
* Time O(N) | Space O(1)
173+
* @param {number[]} nums
174+
* @return {number}
175+
*/
176+
var findDuplicate = function(nums) {
177+
const duplicate = negativeMarking(nums);/* Time O(N) */
178+
179+
restoreToPositiveNumbers(nums); /* Time O(N) */
180+
181+
return duplicate;
182+
}
183+
184+
const negativeMarking = (nums) => {
185+
for (let i = 0; i < nums.length; i++) {/* Time O(N) */
186+
const curr = Math.abs(nums[i]);
187+
188+
const isNegative = nums[curr] < 0;
189+
if (isNegative) return curr;
190+
191+
nums[curr] *= -1;
192+
}
193+
194+
return -1
195+
}
196+
197+
const restoreToPositiveNumbers = (nums) => {
198+
for (let i = 0; i < nums.length; i++) {/* Time O(N) */
199+
nums[i] = Math.abs(nums[i]);
200+
}
201+
}
202+
203+
/**
204+
* https://leetcode.com/problems/find-the-duplicate-number/
205+
* Time O(N) | Space O(1)
206+
* @param {number[]} nums
207+
* @return {number}
208+
*/
209+
var findDuplicate = function(nums, start = 0) {
210+
const swap = (arr, a, b) => [arr[a], arr[b]] = [arr[b], arr[a]];
211+
212+
const isSame = () => nums[start] === nums[nums[start]];
213+
while (!isSame()) {/* Time O(N) */
214+
swap(nums, start, nums[start]);
215+
}
216+
217+
return nums[start];
218+
}
219+
220+
/**
221+
* https://leetcode.com/problems/find-the-duplicate-number/
222+
* Time O(N) | Space O(1)
223+
* @param {number[]} nums
224+
* @return {number}
225+
*/
226+
var findDuplicate = function(nums) {
227+
if (!nums.length) return -1
228+
229+
let [ slow, fast ] = moveFast(nums); /* Time O(N) */
230+
[ slow, fast ] = moveSlow(nums, slow, fast);/* Time O(N) */
231+
232+
return slow;
233+
};
234+
235+
const moveFast = (nums, start = 0) => {
236+
let [ slow, fast ] = [ nums[start], nums[nums[start]] ];
237+
238+
const isSame = () => slow === fast;
239+
while (!isSame()) { /* Time O(N) */
240+
slow = nums[slow];
241+
fast = nums[nums[fast]];
242+
}
243+
244+
fast = start;
245+
246+
return [ slow, fast ];
247+
}
248+
249+
const moveSlow = (nums, slow, fast) => {
250+
const isSame = () => slow === fast;
251+
while (!isSame()) { /* Time O(N) */
252+
slow = nums[slow];
253+
fast = nums[fast];
254+
}
255+
256+
return [ slow, fast ];
257+
}

0 commit comments

Comments
 (0)
Please sign in to comment.