430.扁平化多级双向链表(链表、dfs)

245 阅读1分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。

每日刷题第30天 2021.1.26

扁平化多级双向链表

题目

  • 多级双向链表中,除了指向下一个节点和前一个节点指针之外,它还有一个子链表指针,可能指向单独的双向链表。这些子列表也可能会有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。
  • 给你位于列表第一级的头节点,请你扁平化列表,使所有结点出现在单级双链表中。

示例

示例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]
  • 解释:

  • 输入的多级列表如下图所示: image.png

  • 扁平化后的链表如下图: image.png

示例2

输入:head = [1,2,null,3]
输出:[1,3,2]
解释:

输入的多级列表如下图所示:

  1---2---NULL
  |
  3---NULL

示例3

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

提示

  • 节点数目不超过 1000
  • 1 <= Node.val <= 10^5

解法

  • 使用dfs深度优先遍历,先遍历child,再遍历next
    • 当前节点没有child,则继续往后遍历next
    • 当前节点有child,则往下遍历child节点
  • 注意1⚠️:不要在dfs遍历的过程中去修改next指针的指向,否则会有死循环情况。
  • 解决方法:在dfs遍历的过程中,只做记录节点的操作,最后再将记录好的节点,依次连接成一个新的节点进行返回。
  • 注意⚠️2:函数的返回值要多注意,不要题目要求返回一个node头节点,而自己返回的是一个数组!!!!
  • 利用 flatten 函数本身的含义(将链表头为 head的链表进行扁平化,并将扁平化后的头结点进行返回),我们可以很容易写出递归版本。
  • 为防止空节点等边界问题,起始时建立一个哨兵节点 dummy指向 head,然后利用 head 指针从前往后处理链表:
  • 当前节点 head 没有 child 节点:直接让指针后即可,即 head = head.next
  • 当前节点 headchild 节点:将 head.child 传入 flatten 函数递归处理,拿到普遍化后的头结点 chead,然后将 headchead 建立“相邻”关系(注意要先存起来原本的 tmp = head.next 以及将 head.child 置空),然后继续往后处理,直到扁平化的 chead 链表的尾部,将其与 tmp 建立“相邻”关系。
  • 重复上述过程,直到整条链表被处理完。
/**
* // Definition for a Node.
* function Node(val,prev,next,child) {
* this.val = val;
* this.prev = prev;
* this.next = next;
* this.child = child;
* };
*/

/**
* @param {Node} head
* @return {Node}
*/

var flatten = function(head) {
  let ans = [];
  function dfs (node) {
    if (node == null) return;
    // console.log('node', node.val);
    ans.push(node);
    if(node.child != null) dfs(node.child);
    if(node.next != null) dfs(node.next);
  }
  dfs(head);
  // console.log('ans',ans);
  let result = ans[0];
  let resultAns = result;
  for (let i = 0; i < ans.length - 1; i++) {
    result.next = ans[i + 1];
    result.next.prev = result;
    result.child = null;
    result = result.next;
  }
  return resultAns;
};

附录

  • dfs:递归写法 -> 深度优先遍历
  • bfs:队列写法 -> 广度优先遍历