前端算法小白攻略4-leetcode旋转链表

248 阅读2分钟

前言

让链表成闭环然后转起来帮我们解决问题,那么这就是我们用来解决旋转链表算法题的方法了

分析题目

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

图片.png 图片.png

以下我们定义链表节点总数为size:

  1. 首先从上面两张图我们可以分析出,将链表每个节点向右移动k个位置,其实就是将连接成环的链表向右旋转k个节点
  2. 旋转两个节点可以理解为环尾部移动过来到原本环首部k个节点
    • 比如k=1,size=5,那么5移动到环首,断开第(size-k)个节点即断开成环后head起第4个节点,即可得到5->1->2->3->4;
    • k=2,size=5,那么4,5移动到环首,断开第(size-k)个节点即断开成环后head起第3个节点,即可得到4->5->1->2->3;
    • 因为k是可能会大于链表节点的总数的,那我们需要对k取余操作,如果size是k的倍数相当于没有移动的,所以最后的余数才是我们节点真正移动的位置k%size,那么最后断开成环链表的第(size-k%size)个节点即可获得我们的最终链表

开始解题

var rotateRight = function(head, k) {
  if(!head) return null;
  let pre = head,cur = head,size=1;  // 1、size从1开始,因为我们当前pre节点已经在第一个节点了
  while(pre.next) { // 2、这一步循环是为了让pre指针走到链表的最后一个节点,             
      size += 1;    // 如果pre的next指向null说明走到最后一个节点了,即pre.next为假跳出循环
      pre = pre.next;
  }
  pre.next = cur;  // 3、让pre.next指向cur即让cur成为pre的下一个节点,即链表的尾首相接成环;
  for(let i=0; i < size - k%size -1; i++) {  // 4、链表成环后就要考虑断开第几个节点拿到旋转后的链表
      cur = cur.next;  // 首先让cur指针从head节点移动到需要断开**指向下个节点的指针**的节点上
  }                    // size - k%size -1这里我们size-k/%为什么要减1呢,因为我们cur指针已经在第一个节点上了
  pre = cur.next;      // 5、要断开当前节点与下个节点的指向时,首先保存下个节点,避免丢失丢失后面的节点
  cur.next = null;    // 断开cur所指向节点的下一个指向,那此时cur指向的节点为我们的尾节点
  return pre;         // pre所指向的就是我们新链表的头节点
};