|
| 1 | +// Return Kth to Last: Implement an algorithm to find the kth to last element of a singly linked list. |
| 2 | + |
| 3 | +const assert = require("assert"); |
| 4 | + |
| 5 | +class LinkedListNode { |
| 6 | + constructor(val, next) { |
| 7 | + this.val = val === undefined ? null : val; |
| 8 | + this.next = next === undefined ? null : next; |
| 9 | + } |
| 10 | +} |
| 11 | + |
| 12 | +const arrayToLinkedList = (arr) => { |
| 13 | + let tail = null; |
| 14 | + for (let i = arr.length - 1; i >= 0; i--) { |
| 15 | + tail = new LinkedListNode(arr[i], tail); |
| 16 | + } |
| 17 | + return tail; |
| 18 | +}; |
| 19 | + |
| 20 | +/** |
| 21 | + * Returns the kth to last node in a linked list |
| 22 | + * @param {LinkedListNode} list input linked list |
| 23 | + * @param {number} k element index from the right which we wish to return |
| 24 | + * @return {null} |
| 25 | + * |
| 26 | + * In this approach, we utilize two pointers, `fast` and `slow` to keep track of how far we've traveled through the |
| 27 | + * linked list. We make `fast` travel K steps, before `slow` can start traveling. Then we iterate through both lists |
| 28 | + * until `fast` reaches the end. At that point, we know that the `slow` traversal is the kth to last value. |
| 29 | + * |
| 30 | + * Runtime: O(N) |
| 31 | + * Space: O(1) |
| 32 | + * |
| 33 | + */ |
| 34 | +const returnKthToLast = (list, k) => { |
| 35 | + let fast = list; |
| 36 | + let slow = list; |
| 37 | + |
| 38 | + while (k > 0) { |
| 39 | + if (!fast) return null; |
| 40 | + fast = fast.next; |
| 41 | + k -= 1; |
| 42 | + } |
| 43 | + while (fast !== null) { |
| 44 | + fast = fast.next; |
| 45 | + slow = slow.next; |
| 46 | + } |
| 47 | + return slow.val; |
| 48 | +}; |
| 49 | + |
| 50 | +describe(module.filename, () => { |
| 51 | + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
| 52 | + const linkedList = arrayToLinkedList(arr); |
| 53 | + for (let i = 1; i < arr.length + 1; i++) { |
| 54 | + it(`should return the ${i}th to last element in the linked list`, () => { |
| 55 | + const kthElement = returnKthToLast(linkedList, i); |
| 56 | + const expectedKthElement = arr[arr.length - i]; |
| 57 | + assert.equal(kthElement, expectedKthElement); |
| 58 | + }); |
| 59 | + } |
| 60 | + it("should return null when K is out of bounds", () => { |
| 61 | + const smallArr = [1, 2]; |
| 62 | + const smallLinkedList = arrayToLinkedList(smallArr); |
| 63 | + const bigK = 5; |
| 64 | + |
| 65 | + const kthElement = returnKthToLast(smallLinkedList, bigK); |
| 66 | + const expectedKthElement = null; |
| 67 | + assert.equal(kthElement, expectedKthElement); |
| 68 | + }); |
| 69 | +}); |
0 commit comments