反转链表总结

反转链表总结

在这里插入图片描述

题目描述

[输入一个链表,反转链表后,输出新链表的表头。]
在这里插入图片描述

基础定义

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
struct ListNode {
    int val;
    struct ListNode* next;
    ListNode(int x) : val(x), next(nullptr){}
};

代码-递归版

ListNode* reverseListRecursion(ListNode* head) {
    // base case : 只有一个头结点,反转自身
    if (head->next == nullptr)
        reurn head;
    // 递归
    ListNode* last = reverseListRecursion(head->next);
    head->next->next = head;
    head->next = nullptr;
    return last;
}

代码-非递归

// 相当于反转结点 head 到结点 nullptr 之间的结点 [head, nullptr)
ListNode* reverseList(ListNode* head) {
    if (head == nullptr)
        return nullptr;
    ListNode* pre = nullptr, *cur = head, *nex = head;
    while(cur != nullptr) {
        nex = nex->next;
        cur->next = pre;
        pre = cur;
        cur = nex;
    }
    return pre;
}

拓展

反转链表的前 n 个结点

// 和反转整个链表不同的是,头结点 head 不是终端结点,所以需要记录它的后继结点。
ListNode* successor = nullpter;			// 后继结点
ListNode* reverseN(ListNode* head, int n) {
    // base case : n = 1 反转一个元素
    if (n == 1) {
        successor = head->next;
        return head;
    }
    ListNode* last = reverseN(head->next, n - 1);
    head->next->next = head;
    head->next = successor;
    return last;
}

反转链表的一部分

// 反转索引 [m, n] 部分的链表
ListNode* reverseBetween(ListNode* head, int m, int n) {
    // base case : m = 1 ,就是反转前 n 个结点
    if (m == 1)
        return reverseN(head, n);
    /*
    	将 head 的索引视为 1,是从第 m 个元素开始反转;
    	如果将 head->next 的索引视为 1,反转区间应该是从第 m - 1 个元素开始
    */
    head->next = reverseBetween(head->next, m - 1, n - 1);
    return head;
}

反转结点 a 到 结点 b 之间的结点

// 结点 [a, b) 注意和反转链表(非递归)比较:将 b 换成 nullptr 就相当于
// 反转整个链表
ListNode* reverseBetweenAB(ListNode* a, ListNode* b) {
    ListNode* pre = nullptr, *cur = a, *nex = a;
    while(cur != b) {
        nex = nex->next;
        cur->next = pre;
        pre = cur;
        cur = nex;
    }
    return pre;
}

如何 k 个一组反转链表

ListNode* reverseKGroup(ListNode* head, int k) {
    if (head == nullptr)
        return nullptr;
    // 区间 [a, b) 包含 k 个待反转元素
    ListNode* a, b;
    a = b = head;
    for (int i =  0; i < k; ++i) {
        // 不足 K 个元素,不需要反转, base case
        if (b === nullptr)
            return head;
        b = b->next;
    }
    // 反转前 k 个元素
    ListNode* newHand = reverseBetweenAB(a, b);
    // 递归反转后续链表并拼接
    a->next = reverseKGroup(b, k);
    return newHand;
}

解释下 for 循环之后的几句代码,注意reverse函数是反转区间在[a, b),所以情形是这样的:

反转k个结点
[注意] 该图片来自图中所示公众号。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值