Leetcode 206 题 反转链表

题目描述

反转一个单链表。

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


思路分析

「原地逆置」

利用三指针 pre、cur 和 next 三个连续的指针,分别指向前一个节点、当前节点以及当前节点的下一个节点。
在这里插入图片描述
在原地进行逆置,cur.next = pre,那么 cur 就会和后面的节点开连接,为了避免这一问题,需要使用 next 指针提前保存 cur 后面的节点。
在这里插入图片描述

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode temp = null;

        while(cur != null) {
            temp = cur.next; // 记录当前节点的下一个节点
            cur.next = pre; // 当前节点指向前一个节点
            pre = cur; // pre指针后移
            cur = temp; // cur指针后移
        }

        return pre;
    }
}

「头插法」

构建一个哑节点,并同时遍历链表,将遍历到的节点插入到哑节点之后。

class Solution {
    public ListNode reverseList(ListNode head) {
        // 构建哑节点
        ListNode dummy = new ListNode(0);
        ListNode node = head;
        ListNode temp = null;

        while (node != null) {
            // 保存下一个节点
            temp = node.next;
            // 插入节点头部
            node.next = dummy.next;
            dummy.next = node;
            // node指针后移
            node = temp;
        }

        return dummy.next;
    }
}

「栈的使用」

可以利用栈将全部节点都压入栈中,取数据时,链表后面的节点自然就被放在了栈顶,重新进行指针的指向即可。不过这里需要注意的是,出栈时,每个节点的 next 指针都指向了新的节点,唯独头节点的指针是我们的处理盲区,因此我们需要进行 head.next = null 的操作,否则将会出现循环链表。

class Solution {
    public ListNode reverseList(ListNode head) {
        Stack<ListNode> stack = new Stack<>();
        while (head != null) {
            stack.push(head);
            head = head.next;
        }

        ListNode dummy = new ListNode(0);
        ListNode temp = dummy;
        while (!stack.empty()) {
            temp.next = stack.pop();
            temp = temp.next;
        }

        temp.next = null;
        return dummy.next;
    }
}

「递归操作一」

利用递归进行链表操作,递归中需要做的事情必然是获得当前节点的下一个节点 next,然后将 next 节点的指针指向当前节点 cur。

因此,递归的返回条件也就很明显了,只要当前节点的下一个节点为空,即 cur.next == null,就可以直接返回了,返回当前节点。

这样就可以不断进行递归了,直到所有的指针都逆置,指向它的前一个节点。

private ListNode reverse(ListNode cur) {
    if (cur.next == null) return cur;
    ListNode nex = reverse(cur.next);
    nex.next = cur;
    return cur;
}

当然这样子还不够,虽然所有指针都被逆置了,但是我们可没法获得逆置后的头节点,因此,我们需要有一个辅助节点来帮助我们获得头节点。

ListNode node = null;
private ListNode reverse(ListNode cur) {
    if (cur.next == null) {
        node = cur;
        return cur;
    }
    ListNode nex = reverse(cur.next);
    nex.next = cur;
    return cur;
}

另外,这里也需要对头节点进行处理,避免循环链表。完整的代码如下:

class Solution {
    ListNode node = null;
    public ListNode reverseList(ListNode head) {
        if (head == null) return node;
        head = reverse(head);
        head.next = null;
        return node;
    }

    private ListNode reverse(ListNode cur) {
        if (cur.next == null) {
            node = cur;
            return cur;
        }
        ListNode nex = reverse(cur.next);
        nex.next = cur;
        return cur;
    }
}

「递归操作二」

前面的代码中我们遇到的一个问题是无法获得逆置后链表的头节点,因此我们需要使用一个辅助节点来帮助我们保存头节点。

那能不能不使用这个辅助节点,直接通过递归来返回逆置后的头节点呢?答案是可以的。

既然我们所返回的是逆置后的头节点,那就返回不了当前节点了,那该如何逆置呢?很显然 cur.next.next = cur。

完整代码如下,同样的,这里也需要对头节点进行处理,避免循环链表。

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null) return null;
        ListNode tail = reverse(head);
        head.next = null;
        return tail;
    }

    private ListNode reverse(ListNode cur) {
        if (cur.next == null) return cur;
        ListNode tail = reverse(cur.next);
        cur.next.next = cur;
        return tail;
    }
}

技术公众号:小猿君的算法笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值