python求根节点下的节点数_LeetCode每日一题:填充每个节点的下一个右侧节点指针...

​二叉树 层序遍历

哒哒哒哒哒~ 第二篇题解来啦~

今天做的还是二叉树,关于二叉树的层序遍历,同样实现了简单解法和优化解法。

题目

LeetCode117:填充每个节点的下一个右侧节点指针 II

题目描述

下面是leetcode的原题描述,建议直接看示例和输入输出,我觉得题目前面部分的描述不是很清晰。

给定一个二叉树

struct Node {

int val;

Node *left;

Node *right;

Node *next;

}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

进阶:只能使用常量级额外空间。

使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

示例

输入:root = [1,2,3,4,5,null,7]

输出:[1,#,2,3,#,4,5,7,#]

解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。

提示:树中的节点数小于 6000

-100 <= node.val <= 100

题解

由于原题的描述有点绕,我更简单的描述一下这道题的题意。根据上面的示例和输入输出,实际上,这道题要做的是:对于二叉树的每一层上的每个节点,如果这个节点存在右兄弟节点,则其next指针指向右兄弟节点,如果没有右兄弟节点则指空。或者说每一层为从走到右的链表。

暴力求解

根据题意很容易想到二叉树的层序遍历,从上层到下层,每一层中从左到右遍历,然后改指针就行。那具体怎么实现呢?我们先暴力求解。

用变量cur_layer表示当前遍历层,next_layer表示下一层。两个变量均为数组类型,并且按照从左到右的顺序存储节点。

初始化:cur_layer=[root],next_layer=[]

当cur_layer不空时循环:

1. 查找next_layer,并从左到右添加节点。

对于cur_layer中的每个节点node:

如果node.left存在,则加入next_layer

如果node.right存在,则加入next_layer

2. 对于cur_layer数组内的每个元素cur_layer[i],将其next指针指向其右兄弟节点。

cur_layer[i].next=cur_layer[i+1]

3. 两数组更新,cur_layer=next_layer,next_layer=[],开始下一轮循环。

Python实现

# Definition for a Node.

class Node:

def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):

self.val = val

self.left = left

self.right = right

self.next = next

class Solution:

def connect(self, root: 'Node') -> 'Node':

if not root:

return root

cur_layer = [root]

next_layer = []

while cur_layer:

# find nodes in next layer

for node in cur_layer:

if node.left:

next_layer.append (node.left)

if node.right:

next_layer.append (node.right)

# set next point

for i in range (len (cur_layer) - 1):

cur_layer[i].next = cur_layer[i + 1]

# update

cur_layer[-1].next = None

cur_layer = next_layer

next_layer = []

return root

结果

复杂度分析

时间复杂度:每个节点只遍历一遍,时间复杂度O(n)

空间复杂度:引入两个数组cur_layer,next_layer,空间复杂度O(n)

进阶求解

题目进阶部分要求使用常量级空间复杂度。暴力求解中,我们为了保证每一层内的遍历顺序从左到右,使用了两个额外的数组记录遍历顺序,要优化,首先要解决:如何用几个变量也能保证遍历顺序。这道题的目的是,用next指针,从左到右将兄弟节点连成链表。对于链表,我们只要知道头节点就可以遍历剩余节点,同时它又是一棵树,只要我们知道第i层的链表结构,就可以根据该层上每个节点的左右孩子节点信息,将i+1层的节点连成链表。因此,求解的核心思想是:利用第i层的链表结构,确定i+1层节点的链接关系。

具体算法流程:

引入变量cur_head当前层头节点,cur_node当前节点,next_head下一层头节点,last下一层上一个添加next指针的节点。

1. 初始化cur_head=root,cur_node=root

2. 当cur_head不为空(还有层未遍历)时循环:

2.1 next_head=None,last=None

2.2 对于层内的每个节点cur_node

2.2.1 如果cur_node.left存在

如果next_head为空,则cur_node.left节点为下一层的头结点

如果last不为空,则说明cur_node.left的上一个节点为last, 将last的next指针指向cur_node.left

将last指针更新为cur_node.left

2.2.2 如果cur_node.right存在

如果next_head为空,则cur_node.right节点为下一层的头结点

如果last不为空,则说明cur_node.tight的上一个节点为last, 将last的next指针指向cur_node.right

将last指针更新为cur_node.right

2.2 当前层遍历结束,cur_head指向下一层的头结点

3. 结束,所有层遍历完,放回添加完next指针的树。

备注:算法流程中的2.2.1 和2.2.2 中存在重复逻辑,可以抽象出来,具体见代码实现的add_next方法。

由于每一个节点的next指针默认为None,所以每一层的最后一个节点不需要再指空。

下图以示例为例子,展开描述算法流程。

初始化cur_head=1,cur_node=1 [图1]

cur_head不为空, next_head=None,last=None [图1]cur_node.left(2)存在,next_head为空,将next_head设为2, last设为2 [图2]

cur_node.right(3)存在,last的next指针指向3,last=3 [图2]

1的next为空,没有右边兄弟节点,第一层循环结束,cur_head移到下一层next_head(2),cur_node=2, next_head=None,last=None [图3]cur_node.left(4)存在,next_head为空,将next_head设为4, last=4 [图3]

cur_node.right(5)存在,4的next指针指向5,last=5 [图3]

cur_node=cur_node.next(3),cur_node.left不存在

cur_node.right(7)存在,last(5)的next指针指向7,last=7 [图4]

3的next为空,没有右边兄弟节点,第二层循环结束,ctuur_head移到下一层next_head(4),cur_node=4, next_head=None,last=None [图5]

cur_node 4 没有左右子节点,右移 [图5];cur_node 5 没有左右子节点,右移 [图6];cur_node 7 没有左右子节点,右移 [图7]

cur_head=next_head, cur_head为空,遍历完所有层,结束[图8]

Python实现

class Solution:

def __init__(self):

self.next_head = None

self.last = None

def add_next(self, next_node):

if not self.next_head:

self.next_head = next_node

if self.last:

self.last.next = next_node

self.last = next_node

def connect(self, root: 'Node') -> 'Node':

if not root:

return root

cur_head = root

while cur_head:

cur_node = cur_head

self.next_head = None

self.last = None

while cur_node:

if cur_node.left:

self.add_next(cur_node.left)

if cur_node.right:

self.add_next (cur_node.right)

cur_node = cur_node.next

cur_head = self.next_head

return root

复杂度分析

时间复杂度:每个节点只遍历一遍,时间复杂度O(n)

空间复杂度:引入了4个变量,空间复杂度O(1)

你可能感兴趣的:(python求根节点下的节点数)