「这是我参与11月更文挑战的第 5 天,活动详情查看:2021最后一次更文挑战」
题目
给你一个链表,每 k
个节点一组进行翻转,请你返回翻转后的链表。
k
是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k
的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 1:
输入: head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
示例 3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
示例 4:
输入:head = [1], k = 1
输出:[1]
提示:
列表中节点的数量在范围 sz 内
1 <= sz <= 5000
0 <= Node.val <= 1000
1 <= k <= sz
进阶:你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
题解
提出问题
- 如何分组反转且在反转过程中,如何保留链表节点不丢失?
分析 迭代
- 从示例1来看待反转的链表,想要将每
k
个节点一组进行反转。 - 首先定义个
temp
虚拟节点,将temp.next
指向头节点 - 定义
pre
指向temp
,定义指针tail
指向pre
所指向的节点。
- 将
tail
指针同时往后移动,直到找到k
个节点
- 定义一个
prev
指向tail
所指向节点的下一个节点。 - 定义
P
所指向head
。 - 定义指针
next
指向P
所指向节点的下一个节点。
- 将P指针所指向的节点指向
prev
指针所指向的节点。
- 将
prev
移动到P
指针所在的位置。 - 将
P
指针移动到next
指针所在的位置。 next
向后移动一位。
- 重复执行上述操作,当
per
指针与tail
指针指向同一个节点的时候说明,整k个节点的链表反转执行完毕。
- 将
pre
指针所指向的节点指向tail
指针所指向的节点。
- 整理一下
pre
指针移动到head
指针所在的位置。
head
指针移动到pre
指针所指节点的下一个节点tail
指向pre
指针所指节点
- 然后
tail
节点再次移动k
步,当tail
节点指向null
,证明后面的节点不足K
个,则返回链表。
- 如果不指向
null
,则继续重复上述操作,直到指向null
为止。
代码实现
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var reverseKGroup = function(head, k) {
let temp = new ListNode(0,head)
let p = temp
do{
p.next = reverse(p.next,k)
for(let i = 0; i < k && p; i++) p = p.next
if(p == null) break
}while(true)
return temp.next
};
var reverse = function(head,n){
let pre = head
let cur = head
let cnt = n
while(--n && pre) pre = pre.next
if(pre == null) return head
pre = null
while(cnt--){
[cur.next,pre,cur] = [pre,cur,cur.next]
// let next = cur.next
// cur.next = pre
// pre = cur
// cur = next
}
head.next = cur
return pre
}