用JavaScript解leetcode第25题-K个一组翻转链表

314 阅读2分钟

前言

翻转前K个节点会的话,这题就很简单。
写代码的思路:翻转前K个节点,未翻转部分的节点数大于K,则迭代翻转,直到未翻转节点数小于k结束。

一、题目描述

详细描述请看:leecode地址
简要描述:

  • 这是一道困难题,但是又不那么难。
  • 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
  • k 是一个正整数,它的值小于或等于链表的长度。
  • 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 示例:

image.png

二、解题

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

}