算法-反转一个单链表

反转一个单链表。

示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

输入处理: head为空直接返回空.

1、迭代法
思路: 设置一个前指针pre和当前指针cur,推进直到cur为空,返回pre。
复杂度分析:
时间: O(n). 逐个推进故 O(n).
空间: O(1). 只用到了常数级额外空间故 O(1).

var reverseList = function(head) {
    let cur = head,pre = null;
    while(cur){
        let temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
        //[cur.next,pre,cur] = [pre,cur,cur.next];
    }
    return pre;
};

2、自递归法 – 反转后尾接
思路: 自递归无法存储推进状态所以无法尾递归,不断将 next 放入递归方法反转链表,结果.next = 当前节点. (Tip: 记得推进结果直到 next.next 为空)
复杂度分析:
时间: O(n). 从最底层两个节点反转开始,每层时间复杂度均为 O(1), 总共 n-1 层递归,故时间复杂度为 O(n).
空间: O(n). 递归调用栈消耗空间,共 n-1 层递归,故空间复杂度为 O(n).

var reverseList = function(head) {
    if (!head || !head.next) return head;
    let next = head.next; // next节点,反转后是最后一个节点
    let reverseHead = reverseList(next);
    head.next = null; // 裁减 head
    next.next = head; // 尾接
    return reverseHead;
};

3、尾递归法
思路: 用 prev 和 curr 存储推进状态,直到 curr 为空则输出结果.
复杂度分析:
时间: O(n). 等同于正常推进,故 O(n).
空间: O(1). 尾递归方式,重复使用一个空间故空间复杂度为 O(1).

var reverseList = function(head) {
    return reverse(null, head);
};

function reverse (prev, curr) {
    if (!curr) return prev;
    // [curr.next, prev, curr] = [prev, curr.next, curr.next];
    let tmp = curr.next;
    curr.next = prev;
    return reverse(curr, tmp);
}

4、转数组后 reduce 构造出链表
思路:模仿自 转换成对应的数字直接相加
复杂度分析:
时间: O(n): 两轮遍历.
空间: O(1): 结果不算额外空间,但确实是非原地反转算法.

var reverseList = function(head) {
    if (!head || !head.next) return head
    const arr = []
    while (head) {
        arr.push(head.val)
        head = head.next
    }
    return arr.reduce((acc, v) => { return { val: v, next: acc } }, null)
};

转载自力扣(LeetCode)
作者:Nodreame
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/js-san-chong-jie-fa-di-gui-wei-di-gui-die-dai-by-n/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值