LeetCode之反转链表

反转链表是笔试、面试中考察频率较高的算法题目。本文给出两种解题思路,并用C++实现编码。
在这里插入图片描述

1. 递归法

递归写法较为简单,但算法效率不高。算法时间复杂度为 O(n), 空间复杂度为 O(n)。
在这里插入图片描述

1.1 思路

递归是函数调用自身的一个过程,可以将问题转换为较小规模的问题进行求解。使用递归法解题时,注意一定不要陷入细节。毕竟人脑的算力是有限的,不能人工维护多个栈。
用递归解题需要考虑以下几点:递归函数效果、递归的较小规模问题、递归的基础条件、递归的返回值。
写递归时,一定要明确递归函数可以达到怎样的效果。本题的效果就是:以头结点head为起点的整个链表反转,并返回新的头结点。
较小规模的问题是:反转以头结点后驱结点为起点的整个链表,并返回新的起点。
递归的基础条件是:只有一个结点的链表,反转后是其自身。如果链表为空,反转之后依旧为空。
递归的返回值:本题用 ListNode* last 接收递归返回值(非基础条件)。

1.2 代码实现

具体代码实现如下

  1. 首先确定基础条件
  2. 解决较小规模问题 reverseList(head->next),得到反转链表,返回新结点 last 。
  3. 较小规模问题解决后,需要将原来的头结点与反转链表相连接。

在这里插入图片描述

  1. 将链表末尾 head 指向NULL
    在这里插入图片描述
/**
 * 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 == NULL)
            return head;
        if(head->next == NULL)
            return head;
        ListNode* last = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return last;
    }
};

1.3 实现细节

算法实现过程需要注意基础条件的写法。尤其是链表为空的情况,因此需要判断链表是否为空和链表是否只有一个结点。空指针情况下, head->next 会报错。

Line 16: Char 18: runtime error: member access within null pointer of type 'ListNode' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:25:18

注意检测下述情况
在这里插入图片描述

2. 迭代法

迭代法(双指针法)原地反转两个结点的指向,算法时间复杂度为 O(n),算法的空间复杂度为 O(1)。
在这里插入图片描述

2.1 思路

迭代法的本质是遍历和更新状态。本题需要遍历整个链表实现反转。链表的指向具有单向性,所有要想实现反转链表,需要3个结点指针:pre,cur 还有 nxt。cur 是遍历链表的结点,pre 是 cur 的前驱, nxt 是 cur 的后继,用来保存 cur->next,否则一次局部反转后,我们就再也找不到 cur 的后继结点了。

遍历的终止条件:遍历链表完成,即 cur == NULL。
遍历的操作:每个结点实现局部反转,cur->next = pre;
更新状态:pre = cur; cur = nxt;
返回值为反转后的链表头结点 pre。

在这里插入图片描述

2.2 代码实现

注意使用 nxt 保存 cur->next。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        ListNode* cur = head;
        

        while(cur != NULL)
        {
            ListNode* nxt = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
};

参考文献

  1. labuladong的算法小抄
  2. LeetCode报错
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值