Skip to content

Commit eb4734f

Browse files
authored
Merge pull request #59 from aikhelis/typescript_solutions_linked_lists
TypeScript: Chapter 3 Linked Lists
2 parents 3bbec04 + 1af9cdd commit eb4734f

8 files changed

+275
-1
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { MultiLevelListNode } from "./ds";
2+
3+
/* Definition of MultiLevelListNode:
4+
class MultiLevelListNode {
5+
val: number;
6+
next: MultiLevelListNode | null;
7+
child: MultiLevelListNode | null;
8+
constructor(val: number){
9+
this.val = val;
10+
this.next = null;
11+
this.child = null;
12+
}
13+
}*/
14+
15+
16+
function flattenMultiLevelList(head: MultiLevelListNode | null): MultiLevelListNode | null {
17+
if (!head)
18+
return head;
19+
let tail: MultiLevelListNode | null = head;
20+
// Find the tail of the linked list at the first level.
21+
while (tail.next !== null)
22+
tail = tail.next;
23+
let curr: MultiLevelListNode | null = head;
24+
// Process each node at the current level. If a node has a child linked list,
25+
// append it to the tail and then update the tail to the end of the extended
26+
// linked list. Continue until all nodes at the current level are processed.
27+
while (curr !== null){
28+
if (curr.child !== null){
29+
tail.next = curr.child;
30+
// Disconnect the child linked list from the current node.
31+
curr.child = null;
32+
while (tail.next !== null)
33+
tail = tail.next;
34+
}
35+
curr = curr.next;
36+
}
37+
return head;
38+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ListNode } from './ds';
2+
3+
/* Definition of ListNode:
4+
class ListNode {
5+
val: number; next: ListNode | null;
6+
constructor(val: number){
7+
this.val = val;
8+
this.next = null;
9+
}
10+
}*/
11+
12+
13+
function linkedListIntersection(headA: ListNode | null, headB: ListNode | null): ListNode | null {
14+
let ptrA = headA, ptrB = headB;
15+
// Traverse through list A with 'ptrA' and list B with 'ptrB'
16+
// until they meet.
17+
while (ptrA !== ptrB) {
18+
// Traverse list A -> list B by first traversing 'ptrA' and
19+
// then, upon reaching the end of list A, continue the
20+
// traversal from the head of list B.
21+
ptrA = ptrA !== null ? ptrA.next : headB;
22+
// Simultaneously, traverse list B -> list A.
23+
ptrB = ptrB !== null ? ptrB.next : headA;
24+
}
25+
// At this point, 'ptrA' and 'ptrB' either point to the
26+
// intersection node or both are null if the lists do not
27+
// intersect. Return either pointer.
28+
return ptrA;
29+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ListNode } from './ds';
2+
3+
/* Definition of ListNode:
4+
class ListNode {
5+
val: number; next: ListNode | null;
6+
constructor(val: number){
7+
this.val = val;
8+
this.next = null;
9+
}
10+
}*/
11+
12+
function linkedListReversal(head: ListNode | null): ListNode | null {
13+
let currNode: ListNode | null = head;
14+
let prevNode: ListNode | null = null;
15+
// Reverse the direction of each node's pointer until 'currNode'
16+
// is null.
17+
while (currNode !== null){
18+
const nextNode: ListNode | null = currNode.next;
19+
currNode.next = prevNode;
20+
prevNode = currNode;
21+
currNode = nextNode;
22+
}
23+
// 'prevNode' will be pointing at the head of the reversed linked
24+
// list.
25+
return prevNode;
26+
}
27+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ListNode } from './ds';
2+
3+
/* Definition of ListNode:
4+
class ListNode {
5+
val: number; next: ListNode | null;
6+
constructor(val: number){
7+
this.val = val;
8+
this.next = null;
9+
}
10+
}*/
11+
12+
function linkedListReversalRecursive(head: ListNode | null): ListNode | null {
13+
// Base cases.
14+
if (!head || !head.next)
15+
return head;
16+
// Recursively reverse the sublist starting from the next node.
17+
const newHead: ListNode | null = linkedListReversalRecursive(head.next);
18+
// Connect the reversed linked list to the head node to fully
19+
// reverse the entire linked list.
20+
head.next.next = head;
21+
head.next = null;
22+
return newHead;
23+
}

typescript/Linked Lists/lru_cache.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
class DoublyLinkedListNode {
2+
key: number; val: number;
3+
prev: DoublyLinkedListNode | null;
4+
next: DoublyLinkedListNode | null;
5+
6+
constructor(key: number, val: number) {
7+
this.key = key;
8+
this.val = val;
9+
this.prev = null;
10+
this.next = null;
11+
}
12+
}
13+
14+
class LRUCache {
15+
capacity: number;
16+
hashmap: Map<number, DoublyLinkedListNode>;
17+
head: DoublyLinkedListNode; tail: DoublyLinkedListNode;
18+
19+
constructor(capacity: number) {
20+
this.capacity = capacity;
21+
// A hash map that maps keys to nodes.
22+
this.hashmap = new Map();
23+
// Initialize the head and tail dummy nodes and connect them to
24+
// each other to establish a basic two-node doubly linked list.
25+
this.head = new DoublyLinkedListNode(-1, -1);
26+
this.tail = new DoublyLinkedListNode(-1, -1);
27+
this.head.next = this.tail;
28+
this.tail.prev = this.head;
29+
}
30+
31+
get(key: number): number {
32+
if (!this.hashmap.has(key))
33+
return -1;
34+
// To make this key the most recently used, remove its node and
35+
// re-add it to the tail of the linked list.
36+
const node = this.hashmap.get(key)!;
37+
this.removeNode(node);
38+
this.addToTail(node);
39+
return node.val;
40+
}
41+
42+
put(key: number, val: number): void {
43+
// If a node with this key already exists, remove it from the
44+
// linked list.
45+
if (this.hashmap.has(key))
46+
this.removeNode(this.hashmap.get(key)!);
47+
const node = new DoublyLinkedListNode(key, val);
48+
this.hashmap.set(key, node);
49+
// Remove the least recently used node from the cache if adding
50+
// this new node will result in an overflow.
51+
if (this.hashmap.size > this.capacity) {
52+
this.hashmap.delete(this.head.next!.key);
53+
this.removeNode(this.head.next!);
54+
}
55+
this.addToTail(node);
56+
}
57+
58+
addToTail(node: DoublyLinkedListNode): void {
59+
const prevNode = this.tail.prev;
60+
node.prev = prevNode;
61+
node.next = this.tail;
62+
prevNode!.next = node;
63+
this.tail.prev = node;
64+
}
65+
66+
removeNode(node: DoublyLinkedListNode): void {
67+
node.prev!.next = node.next;
68+
node.next!.prev = node.prev;
69+
}
70+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { ListNode } from './ds';
2+
3+
/* Definition of ListNode:
4+
class ListNode {
5+
val: number; next: ListNode | null;
6+
constructor(val: number){
7+
this.val = val;
8+
this.next = null;
9+
}
10+
}*/
11+
12+
function palindromicLinkedList(head: ListNode | null): boolean {
13+
// Find the middle of the linked list and then reverse the second half of the
14+
// linked list starting at this midpoint.
15+
const mid = findMiddle(head);
16+
const secondHead = reverseList(mid);
17+
// Compare the first half and the reversed second half of the list
18+
let ptr1 = head, ptr2 = secondHead;
19+
let res = true;
20+
while (ptr2) {
21+
if (ptr1!.val !== ptr2.val) {
22+
res = false;
23+
}
24+
ptr1 = ptr1!.next, ptr2 = ptr2.next;
25+
}
26+
return res;
27+
}
28+
29+
// From the 'Reverse Linked List' problem.
30+
function reverseList(head: ListNode | null): ListNode | null {
31+
let prevNode: ListNode | null = null;
32+
let currNode: ListNode | null = head;
33+
while (currNode) {
34+
const nextNode = currNode.next;
35+
currNode.next = prevNode;
36+
prevNode = currNode;
37+
currNode = nextNode;
38+
}
39+
return prevNode;
40+
}
41+
42+
// From the 'Linked List Midpoint' problem.
43+
function findMiddle(head: ListNode | null): ListNode | null {
44+
let slow: ListNode | null = head;
45+
let fast: ListNode | null = head;
46+
while (fast && fast.next) {
47+
slow = slow!.next;
48+
fast = fast.next!.next;
49+
}
50+
return slow;
51+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ListNode } from './ds';
2+
3+
/* Definition of ListNode:
4+
class ListNode {
5+
val: number; next: ListNode | null;
6+
constructor(val: number){
7+
this.val = val;
8+
this.next = null;
9+
}
10+
}*/
11+
12+
function removeKthLastNode(head: ListNode | null, k: number): ListNode | null {
13+
// A dummy node to ensure there's a node before 'head' in case we
14+
// need to remove the head node.
15+
let dummy: ListNode | null = new ListNode(-1);
16+
dummy.next = head;
17+
let trailer: ListNode | null = dummy;
18+
let leader: ListNode | null = dummy;
19+
// Advance 'leader' k steps ahead.
20+
for (let i = 0; i < k; i++){
21+
leader = leader.next;
22+
// If k is larger than the length of the linked list, no node
23+
// needs to be removed.
24+
if (leader === null)
25+
return head;
26+
}
27+
// Move 'leader' to the end of the linked list, keeping 'trailer'
28+
// k nodes behind.
29+
while (leader.next !== null){
30+
leader = leader.next;
31+
trailer = trailer!.next;
32+
}
33+
// Remove the kth node from the end.
34+
trailer!.next = trailer!.next!.next;
35+
return dummy.next;
36+
}

typescript/Two Pointers/triplet_sum_brute_force.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ function tripletSumBruteForce(nums: number[]): number[][] {
1616
}
1717
}
1818
// [javascript] convert the Set back into an array of triplets.
19-
return Array.from(triplets).map(JSON.parse);
19+
return Array.from(triplets).map((str) => JSON.parse(str));
2020
}

0 commit comments

Comments
 (0)