前端算法小白攻略5-leetcode反转链表1、2

259 阅读3分钟

前言

前面我们整完了几道环形链表相关的题,今天我们来搞反转链表,刚接触可能容易被指针指晕哦! 我们先打个反转链表的基础底,后面我们所有关于反转和节点交换等都是基于此哦!

看题描述

反转链表1 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1:

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

整理思路

由上图我们能够得出以下结论:

  1. 原链表的头节点变成了新链表的尾节点,头节点后的每个节点依次成为了新链表的倒数第2、3、4...个节点
  2. 那么我们定义一个指针pre,让原链表从头节点开始依次成为pre的倒数第1,2,3...个节点,最后返回pre即可得到我们的新链表
  3. 那么如何实现呢?我们从下面的4张图加入指针解析下:

图片.png

  1. 图1: 我们首先定义pre指针指向null,cur指向头节点head
  2. 图2: 因为我们只能一个节点一个节点的往pre指针上添加反转后的节点,所以先反cur,那么我们反之前先定义next指针用来存cur.next及后面的节点,
  3. 图3、4: 让cur指向的head连接pre指向的null,即cur.next = pre(pre是前项节点的代表,用后项cur连接前项),接着让我们的pre指针指向cur就形成了pre => cur => null(3)、pre => cur => head => null,这样一直反转下去就能得到我们的新链表

开始解题

var reverseList = function(head) {
    if(!head) return null;
    let pre = null, cur = head;
    while(cur) {
      let next = cur.next; // 保存后项节点
      cur.next = pre; // 当前遍历节点指向后项目节点
      pre = cur; // 让cur所指节点成为pre的反转节点
      cur = next;  
    }
    return pre;
};

趁热打铁-开始反转链表2

反转链表2 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

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

题目解析

  1. 此道题目要我们反转链表从left到right处的节点
  2. 首先我们得让指针跑到反转起点,然后反转right-left+1个节点即可
  3. 本题可以利用虚拟头节点做下,一般在头节点会发生变化的情况下使用效果比较好,这样返回虚头ret.next就能拿到我们的新链表而不用担心头节点的问题

开始解题

var reverseBetween = function(head, left, right) {
  if(!head) return null;
  let ret = new ListNode(-1,head), pre = ret, cnt = right-left+1; //利用虚头
  while(--left) { // 先让pre跑到left前一个节点
      pre = pre.next;
  }
   pre.next = getReverse(pre.next,cnt); // 用反转起点前的pre连接反转后的链表节点
   return ret.next;
};

var getReverse = function(head,n) {
    let pre = null,cur = head;
    while(n--) {  // 循环n次即反转n个节点
        [cur.next,pre,cur] = [pre, cur,cur.next]; // 利用结构赋值简化反转链表1的处理方式
    }
    head.next = cur; // 因为反转后的尾节点是反转起点head,cur指针指向反转后的尾节点的下一个节点(cur=cur.next循环体最后依次执行)
    return pre;
}