前言
翻转前K个节点会的话,这题就很简单。
写代码的思路:翻转前K个节点,未翻转部分的节点数大于K,则迭代翻转,直到未翻转节点数小于k结束。
一、题目描述
详细描述请看:leecode地址
简要描述:
- 这是一道困难题,但是又不那么难。
- 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
- k 是一个正整数,它的值小于或等于链表的长度。
- 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 示例:
二、解题
2.1 解题思路
翻转前K个节点,未翻转部分的节点数大于K,则迭代翻转,直到未翻转节点数小于k结束。结合这句话看下面
1、如何迭代?
迭代继续的条件:未翻转节点数大于K,节点数小于K则跳出循环。
这里有一妙手。先写一个死循环,在循环体内部,不满足条件则break该循环。
while(1) {
for(let i = 0; i < k && pre; i++ {
pre = pre.next
}
if(!pre) break
}
2、翻转前k个节点
function reverseK(head, k) {
let pre = null, cur = head
// 待反转节点数 小于 k 则不用翻转
for(let i = 0; i < k - 1 && cur; i++) {
cur = cur.next
}
if(!cur) return head
// 走到这里说明节点数 大于 k
// cur指针重新指向head,我们开始正式翻转
cur = head
// 依次调换指针,完成翻转
while(k--) {
const next = cur.next
cur.next = pre
pre = cur
cur = next
}
// 翻转尾head拼未翻转部分
head.next = cur
// 翻转后的头
return pre
}
3、拼接处理
// 这里的pre指针指向已翻转尾, reverseK这个函数用来翻转一组k个节点,返回值是头节点
pre.next = reverseK(head,k)
2.2 代码
详细代码请看:git代码地址
这里问大家一个问题,虚拟头节点什么时候用?
头节点的上个节点不存在,对于一些需要用上个节点的操作就需要单独考虑头节点,用上虚拟头节点就不要单独考虑此类操作了
/**
* 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}
*/
const reverseKGroup = function (head, k) {
// 虚拟头节点
let dummy = new ListNode(-1, head)
// 该指针指向已翻转尾
let pre = dummy
while(1) {
pre.next = reverseK(pre.next, k)
for(let i = 0; i < k && pre; i++) {
pre = pre.next
}
if(!pre) break
}
return dummy.next
}
function reverseK(head, k) {
let pre = null, cur = head
// 待反转节点数 小于 k 则不用翻转
for(let i = 0; i < k - 1 && cur; i++) {
cur = cur.next
}
if(!cur) return head
// 走到这里说明节点数 大于 k
// cur指针重新指向head,我们开始正式翻转
cur = head
// 依次调换指针,完成翻转
while(k--) {
const next = cur.next
cur.next = pre
pre = cur
cur = next
}
// 翻转尾head拼未翻转部分
head.next = cur
// 翻转后的头
return pre
}