Medium
题目描述
给你链表的头节点 head 和一个整数 k 。
交换链表正数第 k 个节点和倒数第 k 个节点的值,然后返回链表的头节点(链表 从 1 开始索引)。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[1,4,3,2,5]
示例 2:
输入:head = [7,9,6,6,7,8,3,0,9,5], k = 5
输出:[7,9,6,6,8,7,3,0,9,5]
提示:
- 链表中节点的数目是
n 1 <= k <= n <= 10^50 <= Node.val <= 100
解题思路
解题思路
这道题要求交换链表中正数第 k 个节点和倒数第 k 个节点的值。我们可以采用多种方法来解决:
方法一:双指针法(推荐)
使用双指针技巧,一次遍历找到两个目标节点:
- 先让第一个指针走 k-1 步,到达正数第 k 个节点
- 保存这个节点,然后让两个指针同时前进
- 当第一个指针到达末尾时,第二个指针正好在倒数第 k 个节点
方法二:两次遍历法
- 第一次遍历计算链表长度 n
- 第二次遍历找到正数第 k 个和第 (n-k+1) 个节点(即倒数第 k 个)
- 交换两个节点的值
方法三:转换为数组
将链表转换为数组,利用索引直接访问和交换,然后重建链表。但这种方法空间复杂度较高。
双指针法最为优雅,只需一次遍历,时间复杂度 O(n),空间复杂度 O(1)。
代码实现
class Solution {
public:
ListNode* swapNodes(ListNode* head, int k) {
ListNode* first = head;
ListNode* second = head;
ListNode* kth = nullptr;
// 找到正数第k个节点
for (int i = 1; i < k; i++) {
first = first->next;
}
kth = first;
// 双指针找到倒数第k个节点
while (first->next) {
first = first->next;
second = second->next;
}
// 交换值
swap(kth->val, second->val);
return head;
}
};
class Solution:
def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
first = second = head
# 找到正数第k个节点
for _ in range(k - 1):
first = first.next
kth = first
# 双指针找到倒数第k个节点
while first.next:
first = first.next
second = second.next
# 交换值
kth.val, second.val = second.val, kth.val
return head
public class Solution {
public ListNode SwapNodes(ListNode head, int k) {
ListNode first = head;
ListNode second = head;
ListNode kth = null;
// 找到正数第k个节点
for (int i = 1; i < k; i++) {
first = first.next;
}
kth = first;
// 双指针找到倒数第k个节点
while (first.next != null) {
first = first.next;
second = second.next;
}
// 交换值
int temp = kth.val;
kth.val = second.val;
second.val = temp;
return head;
}
}
var swapNodes = function(head, k) {
let first = head;
let second = head;
let kth = null;
// 找到正数第k个节点
for (let i = 1; i < k; i++) {
first = first.next;
}
kth = first;
// 双指针找到倒数第k个节点
while (first.next) {
first = first.next;
second = second.next;
}
// 交换值
[kth.val, second.val] = [second.val, kth.val];
return head;
};
复杂度分析
| 复杂度类型 | 双指针法 | 两次遍历法 | 数组转换法 |
|---|---|---|---|
| 时间复杂度 | O(n) | O(n) | O(n) |
| 空间复杂度 | O(1) | O(1) | O(n) |
说明:
- 时间复杂度:所有方法都需要遍历链表,所以都是 O(n)
- 空间复杂度:双指针法和两次遍历法只使用常数额外空间,数组转换法需要 O(n) 的额外空间存储数组
相关题目
. Remove Nth Node From End of List (Medium)
. Swap Nodes in Pairs (Medium)
. Reverse Nodes in k-Group (Hard)