Leetcode(206)——反转链表

Leetcode(206)——反转链表

题目

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

题解

示例 1:

在这里插入图片描述
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

在这里插入图片描述
输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

方法一:递归之尾插法

思路

​​  递归版本稍微复杂一些,其关键在于反向工作。假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?

​​  假设链表为:
n1→…→nk−1→nk→nk+1→…→nm→∅n_1\rightarrow \ldots \rightarrow n_{k-1} \rightarrow n_k \rightarrow n_{k+1} \rightarrow \ldots \rightarrow n_m \rightarrow \varnothingn1nk1nknk+1nm

​​  若从节点 nk+1n_{k+1}nk+1​ 到 nmn_mnm​ 已经被反转,而我们正处于 nkn_knk
n1→…→nk−1→nk→nk+1←…←nmn_1\rightarrow \ldots \rightarrow n_{k-1} \rightarrow n_k \rightarrow n_{k+1} \leftarrow \ldots \leftarrow n_mn1nk1nknk+1nm

​​  我们希望 nk+1n_{k+1}nk+1​ 的下一个节点指向 nkn_knk​ 。所以,nk.next.next=nkn_k.\textit{next}.\textit{next} = n_knk.next.next=nk
​​  需要注意的是 n1n_1n1 的下一个节点必须指向 ∅\varnothing。如果忽略了这一点,链表中可能会产生环。

算法解析:

假设初始链表为 1->2->3->4->5
​​  ​​  
第一轮出栈,head为5,head->next为空,返回5
第二轮出栈,head为4,head->next为5,执行 head->next->next=head 也就是5.next=4,
  ​​  把当前节点的子节点的子节点指向当前节点
​​  ​​  此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
​​  ​​  此时链表为1->2->3->4<-5
​​  ​​  返回节点5
第三轮出栈,head为3,head->next为4,执行 head->next->next=head 也就是4.next=3,
  ​​  此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
  ​​  此时链表为1->2->3<-4<-5
  ​​  返回节点5
第四轮出栈,head为2,head->next为3,执行 head->next->next=head 也就是3.next=2,
  ​​  此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
  ​​  此时链表为1->2<-3<-4<-5
  ​​  返回节点5
第五轮出栈,head为1,head->next为2,执行 head->next->next=head 也就是2.next=1,
  ​​  此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
  ​​  此时链表为1<-2<-3<-4<-5
  ​​  返回节点5
出栈完成,最终头节点5->4->3->2->1

代码实现
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 直到当前结点的下一个结点为空时返回当前结点
        if (!head || !head->next)
            return head;
        ListNode* newHead = reverseList(head->next);// 递归传入下一个节点,目的是为了到达最后一个节点
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
};
复杂度分析

时间复杂度O(N)O(N)O(N) ,其中 NNN 是链表的长度。需要对链表的每个节点进行反转操作。
空间复杂度O(N)O(N)O(N) ,其中 NNN 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 NNN 层。

方法二:迭代之头插法

思路

​​  在方法二中,我们采用头插法+头结点+迭代来实现链表的逆序。

代码实现
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr || head->next == nullptr) return head;
        ListNode* newone = new ListNode(0, nullptr);   // 头结点
        ListNode* tmp = nullptr;
        // 头插法
        while(head != nullptr){
            tmp = head;
            head = head->next;
            tmp->next = newone->next;
            newone->next = tmp;
        }
        tmp = newone;
        newone = newone->next;  // 去除头结点
        delete tmp;// 释放资源
        return newone;
    }
};
复杂度分析

时间复杂度O(N)O(N)O(N) ,其中 NNN 是链表的长度。因为需要遍历链表一次。
空间复杂度O(1)O(1)O(1)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值