diff --git a/typescript/Linked Lists/flatten_multi_level_list.ts b/typescript/Linked Lists/flatten_multi_level_list.ts new file mode 100644 index 0000000..57aa7ec --- /dev/null +++ b/typescript/Linked Lists/flatten_multi_level_list.ts @@ -0,0 +1,38 @@ +import { MultiLevelListNode } from "./ds"; + +/* Definition of MultiLevelListNode: +class MultiLevelListNode { + val: number; + next: MultiLevelListNode | null; + child: MultiLevelListNode | null; + constructor(val: number){ + this.val = val; + this.next = null; + this.child = null; + } +}*/ + + +function flattenMultiLevelList(head: MultiLevelListNode | null): MultiLevelListNode | null { + if (!head) + return head; + let tail: MultiLevelListNode | null = head; + // Find the tail of the linked list at the first level. + while (tail.next !== null) + tail = tail.next; + let curr: MultiLevelListNode | null = head; + // Process each node at the current level. If a node has a child linked list, + // append it to the tail and then update the tail to the end of the extended + // linked list. Continue until all nodes at the current level are processed. + while (curr !== null){ + if (curr.child !== null){ + tail.next = curr.child; + // Disconnect the child linked list from the current node. + curr.child = null; + while (tail.next !== null) + tail = tail.next; + } + curr = curr.next; + } + return head; +} \ No newline at end of file diff --git a/typescript/Linked Lists/linked_list_intersection.ts b/typescript/Linked Lists/linked_list_intersection.ts new file mode 100644 index 0000000..64ee7ea --- /dev/null +++ b/typescript/Linked Lists/linked_list_intersection.ts @@ -0,0 +1,29 @@ +import { ListNode } from './ds'; + +/* Definition of ListNode: +class ListNode { + val: number; next: ListNode | null; + constructor(val: number){ + this.val = val; + this.next = null; + } +}*/ + + +function linkedListIntersection(headA: ListNode | null, headB: ListNode | null): ListNode | null { + let ptrA = headA, ptrB = headB; + // Traverse through list A with 'ptrA' and list B with 'ptrB' + // until they meet. + while (ptrA !== ptrB) { + // Traverse list A -> list B by first traversing 'ptrA' and + // then, upon reaching the end of list A, continue the + // traversal from the head of list B. + ptrA = ptrA !== null ? ptrA.next : headB; + // Simultaneously, traverse list B -> list A. + ptrB = ptrB !== null ? ptrB.next : headA; + } + // At this point, 'ptrA' and 'ptrB' either point to the + // intersection node or both are null if the lists do not + // intersect. Return either pointer. + return ptrA; +} diff --git a/typescript/Linked Lists/linked_list_reversal.ts b/typescript/Linked Lists/linked_list_reversal.ts new file mode 100644 index 0000000..73fe4a0 --- /dev/null +++ b/typescript/Linked Lists/linked_list_reversal.ts @@ -0,0 +1,27 @@ +import { ListNode } from './ds'; + +/* Definition of ListNode: +class ListNode { + val: number; next: ListNode | null; + constructor(val: number){ + this.val = val; + this.next = null; + } +}*/ + +function linkedListReversal(head: ListNode | null): ListNode | null { + let currNode: ListNode | null = head; + let prevNode: ListNode | null = null; + // Reverse the direction of each node's pointer until 'currNode' + // is null. + while (currNode !== null){ + const nextNode: ListNode | null = currNode.next; + currNode.next = prevNode; + prevNode = currNode; + currNode = nextNode; + } + // 'prevNode' will be pointing at the head of the reversed linked + // list. + return prevNode; +} + diff --git a/typescript/Linked Lists/linked_list_reversal_recursive.ts b/typescript/Linked Lists/linked_list_reversal_recursive.ts new file mode 100644 index 0000000..f4ae00b --- /dev/null +++ b/typescript/Linked Lists/linked_list_reversal_recursive.ts @@ -0,0 +1,23 @@ +import { ListNode } from './ds'; + +/* Definition of ListNode: +class ListNode { + val: number; next: ListNode | null; + constructor(val: number){ + this.val = val; + this.next = null; + } +}*/ + +function linkedListReversalRecursive(head: ListNode | null): ListNode | null { + // Base cases. + if (!head || !head.next) + return head; + // Recursively reverse the sublist starting from the next node. + const newHead: ListNode | null = linkedListReversalRecursive(head.next); + // Connect the reversed linked list to the head node to fully + // reverse the entire linked list. + head.next.next = head; + head.next = null; + return newHead; +} diff --git a/typescript/Linked Lists/lru_cache.ts b/typescript/Linked Lists/lru_cache.ts new file mode 100644 index 0000000..8f3ce98 --- /dev/null +++ b/typescript/Linked Lists/lru_cache.ts @@ -0,0 +1,70 @@ +class DoublyLinkedListNode { + key: number; val: number; + prev: DoublyLinkedListNode | null; + next: DoublyLinkedListNode | null; + + constructor(key: number, val: number) { + this.key = key; + this.val = val; + this.prev = null; + this.next = null; + } +} + +class LRUCache { + capacity: number; + hashmap: Map; + head: DoublyLinkedListNode; tail: DoublyLinkedListNode; + + constructor(capacity: number) { + this.capacity = capacity; + // A hash map that maps keys to nodes. + this.hashmap = new Map(); + // Initialize the head and tail dummy nodes and connect them to + // each other to establish a basic two-node doubly linked list. + this.head = new DoublyLinkedListNode(-1, -1); + this.tail = new DoublyLinkedListNode(-1, -1); + this.head.next = this.tail; + this.tail.prev = this.head; + } + + get(key: number): number { + if (!this.hashmap.has(key)) + return -1; + // To make this key the most recently used, remove its node and + // re-add it to the tail of the linked list. + const node = this.hashmap.get(key)!; + this.removeNode(node); + this.addToTail(node); + return node.val; + } + + put(key: number, val: number): void { + // If a node with this key already exists, remove it from the + // linked list. + if (this.hashmap.has(key)) + this.removeNode(this.hashmap.get(key)!); + const node = new DoublyLinkedListNode(key, val); + this.hashmap.set(key, node); + // Remove the least recently used node from the cache if adding + // this new node will result in an overflow. + if (this.hashmap.size > this.capacity) { + this.hashmap.delete(this.head.next!.key); + this.removeNode(this.head.next!); + } + this.addToTail(node); + } + + addToTail(node: DoublyLinkedListNode): void { + const prevNode = this.tail.prev; + node.prev = prevNode; + node.next = this.tail; + prevNode!.next = node; + this.tail.prev = node; + } + + removeNode(node: DoublyLinkedListNode): void { + node.prev!.next = node.next; + node.next!.prev = node.prev; + } +} diff --git a/typescript/Linked Lists/palindromic_linked_list.ts b/typescript/Linked Lists/palindromic_linked_list.ts new file mode 100644 index 0000000..6bce191 --- /dev/null +++ b/typescript/Linked Lists/palindromic_linked_list.ts @@ -0,0 +1,51 @@ +import { ListNode } from './ds'; + +/* Definition of ListNode: +class ListNode { + val: number; next: ListNode | null; + constructor(val: number){ + this.val = val; + this.next = null; + } +}*/ + +function palindromicLinkedList(head: ListNode | null): boolean { + // Find the middle of the linked list and then reverse the second half of the + // linked list starting at this midpoint. + const mid = findMiddle(head); + const secondHead = reverseList(mid); + // Compare the first half and the reversed second half of the list + let ptr1 = head, ptr2 = secondHead; + let res = true; + while (ptr2) { + if (ptr1!.val !== ptr2.val) { + res = false; + } + ptr1 = ptr1!.next, ptr2 = ptr2.next; + } + return res; +} + +// From the 'Reverse Linked List' problem. +function reverseList(head: ListNode | null): ListNode | null { + let prevNode: ListNode | null = null; + let currNode: ListNode | null = head; + while (currNode) { + const nextNode = currNode.next; + currNode.next = prevNode; + prevNode = currNode; + currNode = nextNode; + } + return prevNode; +} + +// From the 'Linked List Midpoint' problem. +function findMiddle(head: ListNode | null): ListNode | null { + let slow: ListNode | null = head; + let fast: ListNode | null = head; + while (fast && fast.next) { + slow = slow!.next; + fast = fast.next!.next; + } + return slow; +} diff --git a/typescript/Linked Lists/remove_kth_last_node.ts b/typescript/Linked Lists/remove_kth_last_node.ts new file mode 100644 index 0000000..9df5830 --- /dev/null +++ b/typescript/Linked Lists/remove_kth_last_node.ts @@ -0,0 +1,36 @@ +import { ListNode } from './ds'; + +/* Definition of ListNode: +class ListNode { + val: number; next: ListNode | null; + constructor(val: number){ + this.val = val; + this.next = null; + } +}*/ + +function removeKthLastNode(head: ListNode | null, k: number): ListNode | null { + // A dummy node to ensure there's a node before 'head' in case we + // need to remove the head node. + let dummy: ListNode | null = new ListNode(-1); + dummy.next = head; + let trailer: ListNode | null = dummy; + let leader: ListNode | null = dummy; + // Advance 'leader' k steps ahead. + for (let i = 0; i < k; i++){ + leader = leader.next; + // If k is larger than the length of the linked list, no node + // needs to be removed. + if (leader === null) + return head; + } + // Move 'leader' to the end of the linked list, keeping 'trailer' + // k nodes behind. + while (leader.next !== null){ + leader = leader.next; + trailer = trailer!.next; + } + // Remove the kth node from the end. + trailer!.next = trailer!.next!.next; + return dummy.next; +} \ No newline at end of file diff --git a/typescript/Two Pointers/triplet_sum_brute_force.ts b/typescript/Two Pointers/triplet_sum_brute_force.ts index 659a795..88d7fb9 100644 --- a/typescript/Two Pointers/triplet_sum_brute_force.ts +++ b/typescript/Two Pointers/triplet_sum_brute_force.ts @@ -16,5 +16,5 @@ function tripletSumBruteForce(nums: number[]): number[][] { } } // [javascript] convert the Set back into an array of triplets. - return Array.from(triplets).map(JSON.parse); + return Array.from(triplets).map((str) => JSON.parse(str)); }