标题:交换链表中的结点
出处:1721. 交换链表中的结点
3 级
给你链表的头结点 head \texttt{head} head 和一个整数 k \texttt{k} k。
交换链表正数第 k \texttt{k} k 个结点和倒数第 k \texttt{k} k 个结点的值后,返回链表的头结点(链表从 1 \texttt{1} 1 开始索引)。
示例 1:
输入: head = [1,2,3,4,5], k = 2 \texttt{head = [1,2,3,4,5], k = 2} head = [1,2,3,4,5], k = 2
输出: [1,4,3,2,5] \texttt{[1,4,3,2,5]} [1,4,3,2,5]
示例 2:
输入: head = [7,9,6,6,7,8,3,0,9,5], k = 5 \texttt{head = [7,9,6,6,7,8,3,0,9,5], k = 5} head = [7,9,6,6,7,8,3,0,9,5], k = 5
输出: [7,9,6,6,8,7,3,0,9,5] \texttt{[7,9,6,6,8,7,3,0,9,5]} [7,9,6,6,8,7,3,0,9,5]
示例 3:
输入: head = [1], k = 1 \texttt{head = [1], k = 1} head = [1], k = 1
输出: [1] \texttt{[1]} [1]
示例 4:
输入: head = [1,2], k = 1 \texttt{head = [1,2], k = 1} head = [1,2], k = 1
输出: [2,1] \texttt{[2,1]} [2,1]
示例 5:
输入: head = [1,2,3], k = 2 \texttt{head = [1,2,3], k = 2} head = [1,2,3], k = 2
输出: [1,2,3] \texttt{[1,2,3]} [1,2,3]
对于有 n n n 个结点的链表,倒数第 k k k 个结点为正数第 n − k + 1 n - k + 1 n−k+1 个结点。定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 n−k+1 个结点之后,将这两个结点的值交换即可。
定位到链表的倒数第 k k k 个结点有两种做法。第一种做法是首先遍历链表得到链表的结点数量 n n n,然后再次遍历链表定位到链表的第 n − k + 1 n - k + 1 n−k+1 个结点;第二种做法是使用两个指针一次遍历定位到链表的倒数第 k k k 个结点。
首先遍历链表得到链表的结点数量 n n n,然后再次遍历链表,分别定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 n−k+1 个结点。从 head \textit{head} head 出发,分别向后移动 k − 1 k - 1 k−1 次和 n − k n - k n−k 次,即可定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 n−k+1 个结点。
定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 n−k+1 个结点之后,交换两个结点的值即可。
下图为示例 1 的交换结点的过程。此时 n = 5 n = 5 n=5, k = 2 k = 2 k=2,因此定位到第 2 2 2 个结点和第 4 4 4 个结点,然后交换两个结点的值。
class Solution {
public ListNode swapNodes(ListNode head, int k) {
int n = 0;
ListNode temp = head;
while (temp != null) {
n++;
temp = temp.next;
}
ListNode node1 = head, node2 = head;
for (int i = 1; i < k; i++) {
node1 = node1.next;
}
for (int i = 1; i < n - k + 1; i++) {
node2 = node2.next;
}
int val1 = node1.val, val2 = node2.val;
node1.val = val2;
node2.val = val1;
return head;
}
}
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表一次得到链表的结点数量,然后遍历链表分别定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 n−k+1 个结点。
空间复杂度: O ( 1 ) O(1) O(1)。
上述解法需要首先遍历一次链表得到链表的结点数量 n n n。其实,链表的结点数量 n n n 不需要事先知道。
用 node 1 \textit{node}_1 node1 和 node 2 \textit{node}_2 node2 分别表示链表的正数第 k k k 个结点和倒数第 k k k 个结点。从 head \textit{head} head 出发向后移动 k − 1 k - 1 k−1 次,即可定位到 node 1 \textit{node}_1 node1。对于 node 2 \textit{node}_2 node2 的定位,可以使用两个指针,这两个指针指向的结点在链表中相差 k k k 个位置。
定位 node 2 \textit{node}_2 node2 时,需要创建临时指针 temp \textit{temp} temp,满足 temp \textit{temp} temp 在 node 2 \textit{node}_2 node2 的后面 k k k 个位置。将 node 2 \textit{node}_2 node2 初始化为 head \textit{head} head,由于 node 1 \textit{node}_1 node1 在 head \textit{head} head 的后面 k − 1 k - 1 k−1 个位置,因此将 temp \textit{temp} temp 初始化为指向 node 1 \textit{node}_1 node1 的后一个结点,即满足 temp \textit{temp} temp 在 node 2 \textit{node}_2 node2 的后面 k k k 个位置;
在初始化 node 2 \textit{node}_2 node2 和 temp \textit{temp} temp 之后,将 node 2 \textit{node}_2 node2 和 temp \textit{temp} temp 同时向后移动,直到 temp \textit{temp} temp 指向 null \text{null} null,此时 node 2 \textit{node}_2 node2 即为链表的倒数第 k k k 个结点。
定位到链表的正数第 k k k 个结点和倒数第 k k k 个结点之后,交换两个结点的值即可。
下图为示例 1 的交换结点的过程。此时 k = 2 k = 2 k=2,因此 temp \textit{temp} temp 在 node 2 \textit{node}_2 node2 后面 2 2 2 个位置。同时向后移动 node 2 \textit{node}_2 node2 和 temp \textit{temp} temp,直到 temp \textit{temp} temp 指向 null \text{null} null, node 2 \textit{node}_2 node2 为链表的倒数第 2 2 2 个结点,然后交换 node 1 \textit{node}_1 node1 和 node 2 \textit{node}_2 node2 的值。
class Solution {
public ListNode swapNodes(ListNode head, int k) {
ListNode node1 = head;
for (int i = 1; i < k; i++) {
node1 = node1.next;
}
ListNode node2 = head, temp = node1.next;
while (temp != null) {
node2 = node2.next;
temp = temp.next;
}
int val1 = node1.val, val2 = node2.val;
node1.val = val2;
node2.val = val1;
return head;
}
}
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表分别定位到链表的正数第 k k k 个结点和倒数第 k k k 个结点。
空间复杂度: O ( 1 ) O(1) O(1)。