# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def swapNodes(self, head: ListNode, k: int) -> ListNode:
first = head
for _ in range(k-1):
first = first.next
kth_from_start = first
slow = head
fast = head
for _ in range(k):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
kth_from_end = slow
kth_from_start.val, kth_from_end.val = kth_from_end.val, kth_from_start.val
return head
// Definition for singly-linked list.
// struct ListNode {
// int val;
// ListNode *next;
// ListNode() : val(0), next(nullptr) {}
// ListNode(int x) : val(x), next(nullptr) {}
// ListNode(int x, ListNode *next) : val(x), next(next) {}
// };
class Solution {
public:
ListNode* swapNodes(ListNode* head, int k) {
ListNode* first = head;
for (int i = 1; i < k; ++i) {
first = first->next;
}
ListNode* kth_from_start = first;
ListNode* slow = head;
ListNode* fast = head;
for (int i = 0; i < k; ++i) {
fast = fast->next;
}
while (fast) {
slow = slow->next;
fast = fast->next;
}
ListNode* kth_from_end = slow;
int temp = kth_from_start->val;
kth_from_start->val = kth_from_end->val;
kth_from_end->val = temp;
return head;
}
};
// Definition for singly-linked list.
// public class ListNode {
// int val;
// ListNode next;
// ListNode() {}
// ListNode(int val) { this.val = val; }
// ListNode(int val, ListNode next) { this.val = val; this.next = next; }
// }
class Solution {
public ListNode swapNodes(ListNode head, int k) {
ListNode first = head;
for (int i = 1; i < k; ++i) {
first = first.next;
}
ListNode kthFromStart = first;
ListNode slow = head;
ListNode fast = head;
for (int i = 0; i < k; ++i) {
fast = fast.next;
}
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
ListNode kthFromEnd = slow;
int temp = kthFromStart.val;
kthFromStart.val = kthFromEnd.val;
kthFromEnd.val = temp;
return head;
}
}
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var swapNodes = function(head, k) {
let first = head;
for (let i = 1; i < k; ++i) {
first = first.next;
}
let kthFromStart = first;
let slow = head;
let fast = head;
for (let i = 0; i < k; ++i) {
fast = fast.next;
}
while (fast) {
slow = slow.next;
fast = fast.next;
}
let kthFromEnd = slow;
let temp = kthFromStart.val;
kthFromStart.val = kthFromEnd.val;
kthFromEnd.val = temp;
return head;
};
Given the head of a singly linked list and an integer k
, you are to swap the values of the k
th node from the beginning and the k
th node from the end of the list (the list is 1-indexed). You must return the head of the modified linked list.
k
is always valid (1 ≤ k ≤ list length).
The problem asks us to swap the values of two specific nodes in a singly linked list: the k
th from the start and the k
th from the end. The challenge is to find these nodes efficiently, especially since singly linked lists don't allow backward traversal.
A brute-force approach would be to traverse the list twice: once to find the total length, and then again to locate both nodes. However, we can optimize this by using two pointers to find the k
th node from the end in a single traversal.
The key insight is that while the k
th node from the start is straightforward to locate, the k
th from the end can be found by advancing a second pointer k
steps ahead and then moving both pointers until the lead pointer reaches the end.
k-1
steps from the head to find the k
th node from the start. Save this node as kth_from_start
.k
th node from the end, use two pointers: fast
and slow
. Move fast
k
steps ahead of slow
.slow
and fast
forward together until fast
reaches the end of the list. At this point, slow
will be at the k
th node from the end.This approach ensures that we only traverse the list at most twice, which is efficient for long lists.
Let's consider the list 1 -> 2 -> 3 -> 4 -> 5
with k = 2
:
2
nd node from the start is 2.2
nd node from the end:
slow
and fast
at head.fast
2 steps ahead: fast
is at node 3.slow
is at node 4, which is the 2nd from the end.1 -> 4 -> 3 -> 2 -> 5
.k
th node from the start and from the end: O(N).k
th node from the start: O(k).k
th node from the end in one traversal: O(N - k).Both approaches have linear time complexity, but the optimized one reduces the number of traversals and is more elegant.
The key to solving the Swapping Nodes in a Linked List problem is efficiently locating both the k
th node from the start and the end. By using a two-pointer technique, we can do this in a single pass without extra space. The solution is elegant because it leverages the properties of singly linked lists and pointer manipulation, resulting in an O(N) time and O(1) space algorithm.