leetcode430:扁平化多级双向链表

https://leetcode.cn/problems/flatten-a-multilevel-doubly-linked-list

你会得到一个双链表,其中包含的节点有一个下一个指针、一个前一个指针和一个额外的 子指针 。这个子指针可能指向一个单独的双向链表,也包含这些特殊的节点。这些子列表可以有一个或多个自己的子列表,以此类推,以生成如下面的示例所示的 多层数据结构

给定链表的头节点 head ,将链表 扁平化 ,以便所有节点都出现在单层双链表中。让 curr 是一个带有子列表的节点。子列表中的节点应该出现在扁平化列表 中的 curr 之后curr.next 之前

返回 扁平列表的 head 。列表中的节点必须将其 所有 子指针设置为 null

简单来说就是把多层的链表通过插入合成一条链表

自用,感觉dfs版比较绕,得多复习几次,很容易出错

方法1:递归

出现这种一级一级嵌套很容易想到使用递归,但是递归的代码没有那么好写

cpp 复制代码
class Solution {
public:
    Node* flatten(Node* head) {
        Node* curr = head;
        while (curr) {
            if (curr->child) {
                Node* next = curr->next;
                Node* childHead = flatten(curr->child);

                // 插入 child 链表
                curr->next = childHead;
                childHead->prev = curr;
                curr->child = nullptr;

                // 找到 child 链表的尾部
                Node* tail = childHead;
                while (tail->next) {
                    tail = tail->next;
                }

                // 把尾部和原来的 next 连接
                if (next) {
                    tail->next = next;
                    next->prev = tail;
                }
            }
            curr = curr->next;
        }
        return head;
    }
};

首先要明确要干什么

在每一层递归中要完成断开原来的连接,把断开的位置接上

在当前层循环中完成两件事,其一是检测当前层的每一个节点的child指针是否为空

其二是完成相关的连接

在if语句内部也完成两件事,分别是平坦化和连接

但是我们会注意到

由于递归使得主链的curr指针总是把之前走过的点又走一遍

比如:这里虽然你已经平坦化,并把下面的部分都插入到了3和4之间,但是由于curr指针仍然在3,想要走到4仍然要沿着绿线走一遍,增加了时间复杂度

所以我们就可以考虑记录每一次的链表末尾,

如果有一个函数能同时完成平坦化并且返回链表末尾的指针就好了,

但是原函数返回的是链表的头指针,因此我们得自己写一个函数辅助

方法2:递归+dfs函数优化

这里参考力扣官方题解

cpp 复制代码
class Solution {
public:
    Node* flatten(Node* head) {
        function<Node*(Node*)> dfs = [&](Node* node) {
            Node* cur = node;
            // 记录链表的最后一个节点
            Node* last = nullptr;

            while (cur) {
                Node* next = cur->next;
                //  如果有子节点,那么首先处理子节点
                if (cur->child) {
                    Node* child_last = dfs(cur->child);

                    next = cur->next;
                    //  将 node 与 child 相连
                    cur->next = cur->child;
                    cur->child->prev = cur;

                    //  如果 next 不为空,就将 last 与 next 相连
                    if (next) {
                        child_last->next = next;
                        next->prev = child_last;
                    }

                    // 将 child 置为空
                    cur->child = nullptr;
                    last = child_last;
                }
                else {
                    last = cur;
                }
                cur = next;
            }
            return last;
        };

        dfs(head);
        return head;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/flatten-a-multilevel-doubly-linked-list/solutions/1013884/bian-ping-hua-duo-ji-shuang-xiang-lian-b-383h/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

其中函数的主要部分就是这个dfs函数

补充:关于lambda表达式

其实只是把「递归函数」定义成 lambda 表达式 ,再存到 std::function 里,以便 lambda 内部能调用自己 (实现递归)。

拆开看就四件事:

  1. std::function<Node*(Node*)>

    一个函数对象类型 ,签名是「接收 Node*,返回 Node*」。

  2. dfs

    变量名,后面用它来递归。

  3. = [&]
    捕获列表

    • [&] 表示「所有外部变量按引用捕获」,这样 lambda 里才能看见并调用 自己(dfs)
  4. (Node* node) { ... }

    真正的函数体,和普通函数写法一模一样。

假如孩子指针全为空,代码执行

cpp 复制代码
class Solution {
public:
    Node* flatten(Node* head) {
        function<Node*(Node*)> dfs = [&](Node* node) {
            Node* cur = node;
            // 记录链表的最后一个节点
            Node* last = nullptr;

            while (cur) {
                Node* next = cur->next;
                last = cur;
                cur = next;
            }
            return last;
        };

        dfs(head);
        return head;
    }
};

这样相当于就遍历了一次链表,返回了最后一个位置,也是没有问题的
相关推荐
熬了夜的程序员1 小时前
【LeetCode】82. 删除排序链表中的重复元素 II
数据结构·算法·leetcode·链表·职场和发展·矩阵·深度优先
熬了夜的程序员3 小时前
【LeetCode】83. 删除排序链表中的重复元素
算法·leetcode·链表
胖咕噜的稞达鸭3 小时前
AVL树手撕,超详细图文详解
c语言·开发语言·数据结构·c++·算法·visual studio
阿林学习计算机4 小时前
红黑树的实现
数据结构
豐儀麟阁贵4 小时前
4.4数组的基本操作
java·开发语言·数据结构·算法
无限进步_4 小时前
【C语言】在矩阵中高效查找数字的算法解析
c语言·开发语言·数据结构·c++·其他·算法·矩阵
Yupureki5 小时前
从零开始的C++学习生活 11:二叉搜索树全面解析
c语言·数据结构·c++·学习·visual studio
草莓工作室5 小时前
数据结构2:线性表1-线性表类型及其特点
c语言·数据结构
再睡一夏就好5 小时前
【C++闯关笔记】STL:deque与priority_queue的学习和使用
java·数据结构·c++·笔记·学习·
遇印记6 小时前
网络运维学习笔记
数据结构·笔记·学习