令人头秃的LeetCode——206.反转链表

题目链接:206. 反转链表

小剧场

第一反应:单链表?反转?就这?
img

随即:开玩笑,5分钟内不把这题秒了,我当场,就把这个电脑屏幕吃掉!
img


later


当事人:我真菜,真的。。。只会暴力求解。。。
emmm

解法一 迭代

假设存在链表1-> 2-> 3-> 4-> 5 -> null,反转链表应该得到null <-1 <-2 <-3 <-4 <-5

为了使用迭代法求解,需要将这个过程分解成相同的步骤:

初始化:null 1-> 2-> 3-> 4-> 5 -> null

第1次:null <-1 2-> 3-> 4-> 5 -> null

第2次:null <-1 <-2 3-> 4-> 5 -> null

。。。

第5次:null <-1 <-2 <-3 <-4 <-5 null

不难发现,每一次步骤的操作是类似的。

由于链表被分成了两部分,需要两个指针进行分别指向。因此,在初始化时,定义prev-> null,定义cur-> head

此后,每一步需要做如下步骤:

  • 由于cur后续需要修改指向,为了防止失联,首先需要定义一个临时节点tempNode用于存放cur的当前指向
  • cur修改指向,指向prev
  • curprev都往后移动

如此循环,直至cur指向null

最后,返回新的头节点prev,大功告成!

public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode cur = head;
        while (cur != null){
            ListNode tempNode = cur.next;
            cur.next = prev;
            prev = cur;
            cur = tempNode;
        }
        return prev;
    }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

解法二 递归

由于链表具备天然的递归性质(头节点->子序列),不难想到利用递归将子序列进行反转,再与头节点重新拼接,从而达到整个链表的反转。

问题在于如何设计重新拼接的过程。

更具体的来说,子序列进行反转后,返回的是反转后子序列的头节点,而重新拼接的过程需要子序列的尾节点指向链表的头节点。因此,问题转移到了如何检索反转后子序列的尾节点。

对于这个问题,需要分析递归过程中链表各节点的指向。

假设存在链表1-> 2-> 3-> null,递归方法ListNode reverseList(ListNode head)的宏观语义:将head指向的链表进行反转,并返回反转后链表的头节点。

第1步:1-> reverseList(2-> 3-> null)

第2步:1-> reverseList(2-> reverseList(3-> null))

第2步(递归返回):1-> reverseList(2-> [null <-3])此时2指向的仍然是3,指向还没改变

第2步(重新拼接):1-> reverseList(null <-2 <-3)注意,拼接结束后需要将head指向null,否则就会变成这样👉1-> reverseList(2-> <-3)3指向2,2指向3,形成循环。

第1步(递归返回):1-> null <-2 <-3

第1步(重新拼接):null <-1 <-2 <-3

结束

不难发现,在递归返回时,head的指向尚未发生改变,且head实际上就是指向反转后子序列的尾节点。这样一来,我们就方便的得到了尾节点,拼接的问题也就迎刃而解了嗷。[]( ̄▽ ̄)*

public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null)
            return head;
        ListNode cur = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return cur;
    }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(n) 递归深度可能达到n层
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页