反转链表

182 阅读3分钟

反转链表1

要求

给一个单链表的头节点 head ,反转链表,并返回反转后的链表。

[1,2,3,4] -> [4,3,2,1]

反转链表1思路

   null -> 1 -> 2 -> 3 -> 4
   
   空指针pre指向null
   cur指向头
   定义一个next指向头.next(防止后面的链表丢失)

   1let next = cur.next
   null        1   ->     2   ->    3   ->   4   ->  null
   (pre)     (cur)      (next)

   2、cur.next = pre
   null   <-   1        2   ->    3   ->   4   ->  null
   (pre)     (cur)    (next)

   3、pre = cur
   null   <-   1        2   ->    3   ->   4   ->  null
             (cur)    (next)
             (pre)

   4、cur = next
   null   <-   1        2   ->    3   ->   4   ->  null
             (pre)    (next)
                      (cur)

   然后再次while判断,进入循环
   1let next = cur.next
   null   <-   1        2   ->    3   ->   4   ->  null
             (pre)    (cur)    (next)
   
   ......

   ......

   重复以上步骤,直到cur指向null,则全部反转完毕
   
   

初步尝试

var reverseList = function (head) {
    if (!head.length) return head;
    let list = [];
    while(head.length){
        list.push(head[head.length-1]);
        head = head.split(0,head.length-1);
    }
    return list
};

结果:false

当数据是数组的话,使用以上代码是可以实现的,但是,题目要求是链表,链表所具有的特性是”松散“,不可使用下标,所以以上代码说是反转数组更为合适

再次尝试

var reverseList = function (head) {
    // 当head为空,直接return
    if (!head) return null;
    // 定义一个空指针,一个head
    let pre = null,
        cur = head;
    while (cur) {
        // 解构赋值写法
        [cur.next, pre, cur] = [pre, cur, cur.next]
        
        // let next = cur.next;
        // cur.next = pre;
        // pre = cur;
        // cur = next;
    }
    return pre
};

结果:true

此处代码实现的思路:反转链表1思路

反转链表2

要求

给单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。

反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

使用 head = 1->2->3->4->5->6->7->8->9 left=6 right=8来举例

思路

当我们需要反转例子链表,达到 head = 1->2->3->4->5->8->7->6->9的结果 可以通过上面的‘反转链表1’来获得灵感:1->2->3->4->5不动,6->7->8反转链表,得到8->7->6,然后再设置指针所指的下一节点,5指向8,6指向9。

代码

代码注释有点多,每行代码都有1到多行的注释,需要的同学可以复制到编辑器里看


var reverseBetween = function (head, left, right) {
    // 使用  head = 1->2->3->4->5->6->7->8->9 left=6 right=8 来举例
    // 判断传进来的head是否为空,为空直接return
    if (!head) return null;

    // 在head前再创建一个节点ret,作用?
    let ret = new ListNode(-1, head),
    // -1(ret) -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

        // 创建一个指针pre,指向我们在head前创建的节点ret
        pre = ret,
        // -1(ret,pre) -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

        // 计算需要反转的节点数
        cnt = right - left + 1;
        // cnt = 8-6+1 = 3

    // 此处while,使用pre找到需要反转的节点的初始位置
    while (--left) {
        pre = pre.next;
        /**
         * 
         * 第一次
         * left=5
         * -1(ret) -> 1(pre) -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
         * 
         * 第二次
         * left=4
         * -1(ret) -> 1 -> 2(pre) -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
         * 
         * ......
         * ......
         * 
         * 第五次
         * left=1
         * -1(ret) -> 1 -> 2 -> 3 -> 4 -> 5(pre) -> 6 -> 7 -> 8 -> 9
         * 
         * */
    }
    // 跳出循环后
    // 此时链表的情况为: -1(ret) -> 1 -> 2 -> 3 -> 4 -> 5(pre) -> 6 -> 7 -> 8 -> 9
    // 把反转的节点的第二个位置,以及反转的节点数,传入reverse
    pre.next = reverse(pre.next, cnt);
    /**
     * 经过reverse函数的处理,return回来的是:pre.next = 8
     * 8 -> 7 -> 6 -> 9
     * 即总体的链表为:-1(ret) -> 1 -> 2 -> 3 -> 4 -> 5(pre) -> 8 -> 7 -> 6 -> 9
     * */ 

    return ret.next;
    // return 1 -> 2 -> 3 -> 4 -> 5(pre) -> 8 -> 7 -> 6 -> 9
};

var reverse = function (head, n) {
    // 此处的head是6,n是3
    let pre = null,
        cur = head;
        // cur = 6

    // 此处while,每反转一次,n--,直到n==0,
    while (n--) {
        // 此处解构赋值意思与反转链表.JS相同
        [cur.next, pre, cur] = [pre, cur, cur.next]
        /**
         * 原本链表结构为: 6 -> 7 -> 8 -> 9
         * 
         * 第一次 n=3
         * cur.next = pre
         * null(pre) <- 6(cur)    7 -> 8 -> 9
         * 
         * pre = cur
         * null <- 6(cur,pre)    7 -> 8 -> 9
         * 
         * cur = cur.next
         * null <- 6(pre)    7(cur) -> 8 -> 9
         * 
         * 
         * 
         * 第二次 n=2
         * cur.next = pre
         * null <- 6(pre) <- 7(cur)  8 -> 9
         * 
         * pre = cur
         * null <- 6 <- 7(cur,pre)  8 -> 9
         * 
         * cur = cur.next
         * null <- 6 <- 7(pre)  8(cur) -> 9
         * 
         * 
         * 
         * 第三次 n=1
         * cur.next = pre
         * null <- 6 <- 7(pre) <- 8(cur)  9
         * 
         * pre = cur
         * null <- 6 <- 7 <- 8(cur,pre)  9
         * 
         * cur = cur.next
         * null <- 6 <- 7 <- 8(pre)  9(cur)
         * 
         * */ 
    }
    // 跳出循环后,此时的pre为: 8(pre) -> 7 -> 6 -> null

    head.next = cur;
    // 6.next = 9
    // 即:8(pre) -> 7 -> 6 -> 9

    return pre;
    // return 8(pre) -> 7 -> 6 -> 9
}