反转单链表的5种方式(Reverse Linked List)

415 阅读2分钟
  • 原题是 leetcode 206题 题目如下
/*
 * @lc app=leetcode id=206 lang=javascript
 *
 * [206] Reverse Linked List
 */
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    
}

解法一:利用数组 反转(缺点增加额外空间)

  • 第一步:先将单链表所有节点(引用类型)存入一个数组
  • 第二步:反转数组
  • 第三步:数组第一个节点指向第二个节点,第二个节点指向第三个节点, ... ... 最后一个节点指向 null
  • 将数组第一个元素(反转后的单链表第一个节点)返回,大功告成

完整代码:

var reverseList = function(head) {
    // method 1  利用数组 反转(缺点增加额外空间)
    let arr = [];
    let root = head;
    if (!head || !head.next) {
        return head;
    }
    while(root) {
        arr.push(root);
        root = root.next;
    }
    arr.reverse();
    let len = arr.length;
    for (let i = 0; i < len; i++) {
        arr[i+1] && (arr[i].next = arr[i+1]);
        !arr[i+1] && (arr[i].next = null);
    }
    return arr[0]
};

解法二:利用两个指针 pre curr 每次往下移动一位

完整代码:

var reverseList = function(head) {
    if (!head || !head.next) {
        return head;
    }
    let pre = head;
    let curr = pre.next;
    let last = curr.next;
    pre.next = null; // 原来的第一个节点 必然指向 null
    while (curr) {
        last = curr.next; // 保留下一个节点
        // 改变指向
        curr.next = pre;
        // pre curr 向下移动一位
        pre = curr;
        curr = last;
    }
    // 最后 curr 必然为 null,pre为之后一个元素,也就是新的单链表奶的似一个节点
    return pre;
};

解法三:在单链表前增加一个辅助节点 pre

思路:

  • 第一步:增加一个辅助节点 pre
  • 第二步:从第二个节点开始,都插入到 pre 的后面

完整代码:

var reverseList = function(head) {
    // method 3 在单链表前面 加一个辅助节点pre,
    // 然后从第二个节点开始 插入到pre后面
    function ListNode(val) {
        this.val = val;
        this.next = null;
    }
    if (!head || !head.next) {
        return head;
    }
    let pre = new ListNode();
    pre.next = head; // 辅助节点 pre
    let root = head;
    while (root) {
        let n = root.next;
        if (root === head) {
            root.next = null;
        } else {
            root.next = pre.next;
            pre.next = root;
        }
        root = n;
    }
    return pre.next;
}

解法四:递归

  • 递归的方式我个人感觉没有其他方式 好理解

完整代码:

var reverseList = function(head) {
    //  method 4 递归去实现
    if (!head || !head.next) {
        return head;
    }
    let originHead = head;
    let rootHead;
    function recursive(node) {
        let nextNode = node.next;
        if(!nextNode) {
            rootHead = node;
            return node;
        }
        let n = recursive(nextNode);
        n.next = node;
        if (node === originHead) {
            node.next = null;
            return rootHead;
        } else {
            return node;
        }
        
    }
    return recursive(head);
}

解法五:巧妙方案

  • 该方法巧妙的利用了一个中间变量 temp
// method 5 终极方案
var reverseList = function(head) {
    var temp = null;
    while(head){
         temp = {
             val:head.val,
             next:temp //这个 temp 每次循环指向的是上一个节点
         };
        head=head.next
    }
    return temp;
};

写在最后:

反转单链表是在面试环节经常遇到的题目,在遇到时,我们可以先说出解法一、二、三、四 到这里基本可以让面试官满意了,最后再拿出终极方案五,必有奇效