// recursion, linked-list, two-pointer
const { LinkedList } = require('../../utils')
// Recursive solutions
/*
Recurse and go to the end passing the head and subsequent nodes as the new head on each call.
After each call, increment i and check if i === k.
If i === k, return the head.
*/
function printKthToLast(head, k) {
if (!head) return 0
const index = printKthToLast(head.next, k) + 1
if (index === k) console.log(k + 'th to last node is ' + head.val)
return index
}
function kthToLast(head, k) {
let i = 0
function inner(head, k) {
if (!head) return null
let node = inner(head.next, k)
i = i + 1
if (i === k) return head
return node
}
return inner(head, k)
}
/*
n = length of linked list
Time Complexity - O(n)
Space complexity - O(n). From recursion stack
*/
/* ---------------------------------------------------------------------------- */
// Iterative
/*
Use the runner technique. Start with two pointers --> p1 and p2.
Move one pointer (p2) k nodes ahead.
Then, move both pointers one node at a time, until p2 hits null.
p1 will be kth node from the end.
For k = 3
Step 1:
p1 p2
1 --> 2 --> 3 --> 4 --> null
Step 2:
p1 p2
1 --> 2 --> 3 --> 4 --> null
Step 3:
p1 p2
1 --> 2 --> 3 --> 4 --> null
^
*/
function kthToLastIterative(head, k) {
let p1 = head,
p2 = head
for (let i = 0; i < k; i++) {
if (!p2) return null //k > size of linked list
p2 = p2.next
}
while (p2) {
p1 = p1.next
p2 = p2.next
}
return p1
}
/*
n = length of linked list
Time Complexity - O(n)
Space complexity - O(1)
*/
/* ---------------------------------------------------------------------------- */
// Tests
function test(cb) {
const ll = new LinkedList()
ll.fromArray([1, 2, 3, 5, 1, 2])
const ll2 = new LinkedList()
ll2.fromArray([1, 2, 3, 4])
const testCases = [
[ll, 3, 5],
[ll2, 3, 2],
[ll2, 5, null],
]
cb(testCases)
}
test((testCases) => {
for (const test of testCases) {
printKthToLast(test[0].head, test[1])
}
})
test((testCases) => {
for (const test of testCases) {
const res = kthToLast(test[0].head, test[1])
res ? console.log(res.val === test[2]) : console.log(res === test[2])
}
})
test((testCases) => {
for (const test of testCases) {
const res = kthToLastIterative(test[0].head, test[1])
res ? console.log(res.val === test[2]) : console.log(res === test[2])
}
})