-
LeetCode题目: reverse-nodes-in-k-group
-
题目描述: 给定一个链表head,以及一个数值k,开始大于0且小于等于head长度一个整数,将k范围内的链表翻转,最终返回修改后的链表!eg1:
list: 1->2->3->4->5;
当k = 2 , output: 2->1->4->3->5
当k = 3 , output: 3->2->1->4->5
-
题目分析: 单链表的特点是当前节点保存了当前节点的值和指向后续节点的值,链表的长度需要遍历得到,因此有两种思路,1.遍历链表获得链表长度,根据k值做分段,在段内改变节点的指向;2.不关心链表的长度,通过数组记录不同的节点,当数组长度 === k之后进行交换,超过nk的节点则顺序添加到新节点。
-
解法一: 通过遍历链表长度,然后从头截取k,2k,3k,对获取的链接做翻转操作。代码如下:
链表遍历函数:
function findLinkListLength(list) { let count = 0; let tmp = list; while(tmp) { tmp = tmp.next count++ } return count; }链表节点交换函数:
function reverse(node, k) { let previous = null; let current = node; let following; let tail = node; for(let i = 0; i < k; i++) { following = current.next; //保存当前节点指向信息 current.next = previous; //交换节点指向 previous = current; current = following; } return [previous, tail, following]; }实现链表的翻转:
const reverseKGroup = function(head, k) { let linkListLength = findLinkListLength(head) let remainingReverses = Math.floor(linkListLength / k); let newHead; let previousTail; while(remainingReverses > 0) { let [front, tail, following] = reverse(head, k); if (remainingReverses === Math.floor(linkListLength / k)) { newHead = front; previousTail = tail; } else { previousTail.next = front; previousTail = tail; } tail.next = following head = following remainingReverses-- } return newHead }; -
解法二: 不关心链表的长短,对链表进行遍历,将节点值保存到数组中并生成节点,当数组长度大于等于k,将数组生成链表;
链表节点生成函数:
const ListNode = (val, next)=>{ return { val: val, next: next === undefined ? null : next } }完整解法:
const reverseKGroup = function(head, k) { const list = []; const pointer = []; while (head) { const node = ListNode(head.val, null); //生成新节点 pointer.unshift(node); if (pointer.length >= k) { while (pointer.length > 0) { list.push(pointer.shift()); } } head = head.next; } while (pointer.length > 0) { list.push(pointer.pop()); } for (let i = 0; i < list.length; i++) { //生成链表 if (i !== list.length - 1) { list[i].next = list[i + 1] } else { list[i].next = null; } } return list[0] }; -
两种解法分析: 第一种解法使用了更多的内存空间,但是通过遍历数组,截取nk范围内的链表节点,直接交换节点指向,在执行时间上更优。整个交换的写法也更符合链表的处理方法;第二种解法则更容易理解,更多的采用了数组的处理方法,使用的内存更少,但是相对的时间复杂度更高。综合来说第一种解法是更符合链表特性,在整体执行效率上更优秀。