K 个一组翻转链表

187 阅读3分钟

给你一个链表,每 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 个节点一组进行翻转,那么k等于1就相当于翻转自己,所以可直接return。既然规则是翻转,我们可以想到把k个节点slice(截取)出来在进行一次reverse翻转便可。当然截取在循环中肯定是要有规则的。由题意可知第一次第从下标第0个开始截取到第k个就是我们需要翻转的节点,所以可自定义n=0我们的默认下标,每次循环完成我们让n+=k这便是下次开始截取的下标也是上次截取到的下标(例如0+k依然等于k),既然上次截取的下标得到,每k个节点翻转一次可得出以下截取规则。

  let arr = [1, 2, 3, 4, 5],
       k = 2; //该数据结果应是每2个节点翻转一次。结果应是[2,1,4,3,5]
     function flip(arr, k) {
       let newArr = []; //用于保存结果
       let n = 0; //每次开始截取的下标
       if (arr == 1) return false;
       for (let i = 0; i < arr.length; i++) {
         let sliceArr = arr.slice(n, n + k); //下部分累加已得到每次开始截取的值,+每k个翻转的值
       }
       n += k; //每次循环完成累加得到上次截取到的下标
     }

     flip(arr, k);

2.通过上面可看到我们得到了截取规则。每k个节点翻转一次如果是小于总链表的长度来循环,可想一定是有问题的毕竟下面进行了累加操作来截取。可以想想循环规则节点总数的长度/k便是循环的次数,当然这样依然是有问题的毕竟总结点不可每次正好得到一次整数,题目的后半部分如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。比如 7/2得到3余1 这个1我们需要保持原来的顺序。所以也要一次循环,向上取整 Math.ceil(7/2)便可得到4。完整代码:

  let arr = [1, 2, 3, 4, 5],
       k = 2; //该数据结果应是每2个节点翻转一次。结果应是[2,1,4,3,5]
  function flip(arr, k) {
       if (k == 1) return
       let newArr = []//用于保存结果
       let n = 0; //每次开始截取的下标
       for (let i = 0; i < Math.ceil(arr.length / k); i++) {
         let sliceArr = arr.slice(n, k + n)  /下部分累加已得到每次开始截取的值,+每k个翻转的值
         if (sliceArr.length === k) {
           sliceArr.reverse()  //每次截取完成进行翻转
           newArr.push(...sliceArr);
         } else {
           for (let c=0;c<sliceArr.length;c++){
             newArr.push(sliceArr[c])
           }
         }
         n += k; //每次循环完成累加得到上次截取到的下标
       }
       return newArr
     }