Problem Statement
Given a singly linked list and an integer n
. Find the nth node from the end of the linked list and return its value.
If n
is greater than the length of the list, return a message indicating that the position is out of bounds.
Examples
Example 1:
Input: List 1 -> 2 -> 3 -> 4 -> 5 -> nullptr, N = 2
Output: 4
Explanation: The second node from the last is 4 while 5 is the last node.
Example 2:
Input: List 1 -> 2 -> 3 -> 4 -> 5 -> nullptr, N = 5
Output: 1
Explanation: The fifth node from the last is 1.
Intuition
We can solve this problem using one of the derivation of Two-Pointers
technique | pattern which is Lead and Lag pointers
.
The lead and lag pointer technique involves using two pointers (often referred to as the "lead" and "lag" pointers):
- Lead Pointer: This pointer will be moved
n
steps ahead in the linked list. - Lag Pointer: This pointer will start from the head and will move simultaneously with the lead pointer after the lead pointer has moved
n
steps.
- By moving the lead pointer
n
steps ahead first, the distance between the lead and lag pointers becomesn
nodes. - When the lead pointer reaches the end of the list, the lag pointer will be exactly
n
nodes behind it, hence pointing to the nth node from the end.
Approach
- Initialize both pointers: Start with both pointers (
lead
andlag
) at the head of the linked list. - Advance the lead pointer: Move the
lead
pointern
steps forward. - Check out-of-bounds: If the
lead
pointer reachesnullptr
before completingn
steps, thenn
is larger than the number of nodes in the list. - Move both pointers together: Move both pointers one step at a time until the
lead
pointer reaches the end of the list. - Output: The
lag
pointer will be pointing at the nth node from the end.
Code
#include <iostream>
struct ListNode {
int data;
ListNode* next;
ListNode(int x) : data(x), next(nullptr) {}
};
// Function to find the nth node from the end of the linked list using lead and lag pointers
int findNthFromEnd(ListNode* head, int n) {
ListNode* lead = head; // Lead pointer
ListNode* lag = head; // Lag pointer
// Step 1: Move the lead pointer n steps ahead
for (int i = 0; i < n; ++i) {
if (lead == nullptr) {
std::cout << "Out of bounds" << std::endl;
return -1; // Out of bounds
}
lead = lead->next;
}
// Step 2: Move both pointers until lead reaches the end
while (lead != nullptr) {
lead = lead->next;
lag = lag->next;
}
// Step 3: The lag pointer is now pointing to the nth node from the end
if (lag != nullptr) {
return lag->data;
} else {
std::cout << "Out of bounds" << std::endl;
return -1; // Out of bounds
}
}
// Helper function to print the linked list
void printList(ListNode* head) {
while (head != nullptr) {
std::cout << head->data << " -> ";
head = head->next;
}
std::cout << "nullptr" << std::endl;
}
int main() {
// Create a simple linked list with initial elements
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(4);
head->next->next->next->next = new ListNode(5);
std::cout << "Original list: ";
printList(head);
// Find the 2nd node from the end
int n = 2;
int result = findNthFromEnd(head, n);
if (result != -1) {
std::cout << "The " << n << "th node from the end is: " << result << std::endl;
}
// Find the 5th node from the end
n = 5;
result = findNthFromEnd(head, n);
if (result != -1) {
std::cout << "The " << n << "th node from the end is: " << result << std::endl;
}
// Find the 6th node from the end (Out of bounds)
n = 6;
result = findNthFromEnd(head, n);
if (result != -1) {
std::cout << "The " << n << "th node from the end is: " << result << std::endl;
}
return 0;
}
Complexity Analysis
- Time Complexity:
O(n)
- The function only traverses the list once. First, it moves the
lead
pointern
steps ahead, and then it moves both pointers until thelead
pointer reaches the end. This results in a linear time complexity relative to the number of nodes (n
) in the list.
- The function only traverses the list once. First, it moves the
- Space Complexity:
O(1)
- The solution uses a fixed amount of extra space (two pointers), so the space complexity is constant.