「这是我参与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 <= 50000 <= Node.val <= 10001 <= 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
}