力扣 430. 扁平化多级双向链表

目录

第一站 LeetCode 新手村

前言

430. 扁平化多级双向链表

题目描述

解题思路

代码

总结

题目来源


第一站 LeetCode 新手村


前言

最近玩OJ赛,发现对算法的理解还需要更加扎实,code能力还可以进一步提升,所以做这样一个算法的系列文章,用于记录学习心得,交流经验,更好地进步和成长。


430. 扁平化多级双向链表

题目描述

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

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

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

示例1

输入:head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
输出:[1,2,3,7,8,11,12,9,10,4,5,6]
解释:输入的多级列表如上图所示。
扁平化后的链表如下图:

示例 2

输入:head = [1,2,null,3]
输出:[1,3,2]
解释:输入的多级列表如上图所示。
扁平化后的链表如下图:

 示例 3

输入:head = []
输出:[]
说明:输入中可能存在空列表。

提示

  • 节点数目不超过 1000
  • 1 <= Node.val <= 105

解题思路

预知

LeetCode是核心代码模式,所以只需要考虑核心算法,输入由系统自动完成,最后的输出以return返回;

思路

这道题是一道比较巧妙的题目,巧妙在编程的思路上,在记录结点和结点下一位置时,没有使用双指针而是巧妙利用了程序流程的顺序执行来实现结点的依次遍历和对该结点下一结点的记录;

大的算法就是深度优先搜索和迭代,实现思路请参考代码和注释;

代码

C++

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* prev;
    Node* next;
    Node* child;
};
*/

class Solution {
public:
    Node* flatten(Node* head) {
        function<Node*(Node*)> dfs = [&](Node* node){ //定义结点类型的函数,最后返回结点
            Node* cur = node;    //cur用于遍历整个链表
            Node* last = nullptr; //用于记录链表的最后一个结点(最后一个结点统一指最后一个非空结点)

            while(cur){
                Node* next = cur->next;  //用于记录该结点的下一个结点,该当有孩子时,最终会指向该结点
                if(cur->child){  //判断是否存在子结点
                    Node* child_last = dfs(cur->child);  //迭代进入下一层,若已经到最后一层,child_last会指向链表子的最后一个结点

                    //把该结点的孩子和它自身连接起来,构成双向指针(双链表)
                    next = cur->next;   //用于记录该结点的下一个
                    cur->next = cur->child;  //后向指针
                    cur->child->prev = cur;  //前向指针

                    if(next){   //这里判断下,如果有孩子的结点刚好是尾结点就不作处理
                        child_last->next = next;
                        next->prev = child_last;
                    }

                    cur->child = nullptr; //将拥有child结点的child置为空
                    last = child_last; //更新合成链表的最后一个结点
                }else{
                    last = cur;
                }
                cur = next; //next已在上文声明,所以cur向后移动一个元素
            }
            return last;  //这里是迭代中返回的元素,子链表的最后一个结点
        };
        
        dfs(head);
        return head;
    }
};

 

function<Node*(Node*)> dfs = [&](Node* node)

可能有同学疑问,上面这行代码的含义,又是怎么使用的,其实这是C++中的一种函数定义方式,

例如 function<int(int)> 或 function<String(int)> 等格式的类模板,上边这行代码,

Node*(Node*)是声明结点类型,而[&](Node* node),则是把定义在Node类中的结点赋值给这个函数,让这个函数可以操作相应的链表;

具体的实现原理感兴趣的朋友可以参考这篇文章,讲解很是详细

深入浅出C++的function - 知乎 (zhihu.com)


总结

以上就是今天要讲的内容,本文仅仅简单讲解了《430. 扁平化多级双向链表》这一题目,对深度优先搜索和迭代法结合使用有了进一步的了解。

题目来源

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/flatten-a-multilevel-doubly-linked-list

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值