[路飞]_leetcode 25. K 个一组翻转链表 JavaScript版

410 阅读2分钟

「这是我参与11月更文挑战的第 5 天,活动详情查看:2021最后一次更文挑战

题目来源:LeetCode-52. K 个一组翻转链表

题目

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例 1:

image.png

输入: head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例 2:

image.png

输入: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所指向的节点。

image.png

  • tail指针同时往后移动,直到找到k个节点

image.png

  • 定义一个prev指向tail所指向节点的下一个节点。
  • 定义P所指向head
  • 定义指针next指向P所指向节点的下一个节点。

image.png

  • 将P指针所指向的节点指向prev指针所指向的节点。

image.png

  • prev移动到P指针所在的位置。
  • P指针移动到next指针所在的位置。
  • next向后移动一位。

image.png

  • 重复执行上述操作,当per指针与tail指针指向同一个节点的时候说明,整k个节点的链表反转执行完毕。

image.png

  • pre指针所指向的节点指向tail指针所指向的节点。

image.png

  • 整理一下

image.png

  • pre指针移动到head指针所在的位置。

image.png

  • head指针移动到pre指针所指节点的下一个节点
  • tail指向pre指针所指节点

image.png

  • 然后tail节点再次移动k步,当tail节点指向null,证明后面的节点不足K个,则返回链表。

image.png

  • 如果不指向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
}