东哥带你刷二叉树(思路篇) :: labuladong的算法小抄 #1056
Replies: 117 comments 21 replies
-
东哥,这里我一直搞不懂。
|
Beta Was this translation helpful? Give feedback.
-
@Jiujiale // 3、将原先的右子树接到当前右子树的末端
TreeNode p = root;
while (p.right != null) {
p = p.right;
} 这段就是让原右子树接到原左子树的末尾
|
Beta Was this translation helpful? Give feedback.
-
@ArmandXiao 说的对,其实这题有效率更高的方式,利用二叉树的遍历顺序从而避免 while 循环,不过略难理解。 @Jiujiale |
Beta Was this translation helpful? Give feedback.
-
多谢两位指点 @ArmandXiao @labuladong |
Beta Was this translation helpful? Give feedback.
-
翻转二叉树这个题,中序遍历会对原左节点翻转两次。 |
Beta Was this translation helpful? Give feedback.
-
讲的太好了!!! |
Beta Was this translation helpful? Give feedback.
-
116题根据你的思路,我想的是另一种思路: class Solution {
public:
Node* connect(Node* root) {
if(root==nullptr){
return root;
}
root->next = nullptr;
DFS(root);
return root;
}
void DFS(Node* node){
if(node==nullptr || node->left==nullptr){
return ;
}
node->left->next = node->right;
if(node->next!=nullptr){
node->right->next = node->next->left;
}
DFS(node->left);
DFS(node->right);
}
}; |
Beta Was this translation helpful? Give feedback.
-
TreeNode left = root.left; |
Beta Was this translation helpful? Give feedback.
-
@huangpan2507 明白了,是直接从root将右子节点后面接上 保存的root.left.相当于把原本的右节点内容踹了。接上了左边的链表 |
Beta Was this translation helpful? Give feedback.
-
第三题,为什么我默写的时候思维总是那么别扭。想的是先把右侧接到左侧,然后把左侧接到根上,这样需要判断左侧是否是null。 |
Beta Was this translation helpful? Give feedback.
-
我的解法是先嫁接到左节点: private void dfs(TreeNode node) {
if (node == null) {
return;
}
dfs(node.left);
dfs(node.right);
TreeNode left = node.left;
TreeNode right = node.right;
// 寻找左子树中最后一个右节点
TreeNode lastNodeOfLeftTree = left;
while (lastNodeOfLeftTree != null && lastNodeOfLeftTree.right != null) {
lastNodeOfLeftTree = lastNodeOfLeftTree.right;
}
node.left = null;
// 左节点不为空的时候才嫁接右节点过去;左节点为空的时候,右节点就不动
if (lastNodeOfLeftTree != null) {
lastNodeOfLeftTree.right = right;
node.right = left;
}
} |
Beta Was this translation helpful? Give feedback.
-
东哥的解题方法,神赞! 第二个问题,leetcode 116,我用你的方法但是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: 'Optional[Node]') -> 'Optional[Node]':
# Base Case
if root is None:
return root
connectTwoNode(root.left, root.right)
return root
def connectTwoNode(self, node1, node2):
if node1 is None or node2 is None:
return
node1.next = node2
self.connectTwoNode(node1.left, node1.right)
self.connectTwoNode(node2.left, node2.right)
self.connectTwoNode(node1.right, node2.left)
"""
# 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: 'Optional[Node]') -> 'Optional[Node]':
# Base Case
if root is None:
return root
connectTwoNode(root.left, root.right)
return root
# Preorder
def connectTwoNode(self, node1, node2):
if node1 is None or node2 is None:
return
node1.next = node2
self.connectTwoNode(node1.left, node1.right)
self.connectTwoNode(node2.left, node2.right)
self.connectTwoNode(node1.right, node2.left) |
Beta Was this translation helpful? Give feedback.
-
// 辅助函数
void connectTwoNode(Node node1, Node node2) {
if (node1 == null || node2 == null) {
return;
} 116题,这个 if 判断,因为是完美二叉树,就代表只要 node1 不是 null,node2 就不是 null,反之,node1 只要是 null,node2 也一定是 null,所以 只需要判断 node1 是否为 null 即可满足条件。 我是这么理解的,提交也通过了,东哥我理解的对不? |
Beta Was this translation helpful? Give feedback.
-
114题,既然递归是无敌,何必用while在进入到子串内部呢? class Solution {
public void flatten(TreeNode root) {
flatten1(root);
}
public TreeNode flatten1(TreeNode root) {
if(root==null){
return null;
}
//获取尾部节点
TreeNode endl=flatten1(root.left);
TreeNode endr=flatten1(root.right);
//获取尾部为空时
if(endl==null&&endr==null){
return root;
}else if(endl==null){
return endr;
}else if(endr==null){
root.right=root.left;
root.left=null;
return endl;
}
//右串接入左串尾部,左串接入右边
endl.right=root.right;
root.right=root.left;
root.left=null;
return endr;
}
} |
Beta Was this translation helpful? Give feedback.
-
第二题可以使用层序遍历的方法,里面while循环里面两个for循环,一个负责next指针,一个和原层序遍历一样 |
Beta Was this translation helpful? Give feedback.
-
114题提供一种遍历思路,遍历函数返回子树先序序列的最后一个节点 class Solution {
TreeNode* traversal(TreeNode* root)
{
if (root == nullptr)
return root;
TreeNode* endL = traversal(root->left);
TreeNode* endR = traversal(root->right);
if (endL != nullptr)
{
endL->right = root->right;
root->right = root->left;
root->left = nullptr;
}
return endR ? endR : endL ? endL : root;
}
public:
void flatten(TreeNode* root) {
traversal(root);
}
}; |
Beta Was this translation helpful? Give feedback.
-
114采用前序遍历也可以做,不需要返回节点值,只需要一个指针记录当前节点 class Solution {
public:
TreeNode* cur=nullptr;
void flatten(TreeNode* root) {
if(root==nullptr)return;
cur = root;
TreeNode* pright = root->right;
root->right = root->left;
flatten(root->left);
root->left = nullptr;
cur->right = pright;
flatten(pright);
}
}; |
Beta Was this translation helpful? Give feedback.
-
遍历的方式在返回 void 的情况下,也能实现二叉树拉平 void flatten(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> queue = new LinkedList<>();
flattenNode(root, queue);
TreeNode p = queue.poll();
while (!queue.isEmpty() && p != null) {
TreeNode rightNode = queue.poll();
p.left = null;
p.right = rightNode;
p = p.right;
}
}
void flattenNode(TreeNode node, Queue<TreeNode> queue) {
if (node == null) {
return;
}
queue.add(node);
flattenNode(node.left, queue);
flattenNode(node.right, queue);
} |
Beta Was this translation helpful? Give feedback.
-
第二题, 填充右侧节点的, 我觉得抽象成三个节点其实非常的非常规, 比较难想到,似乎让人眼前一亮.但是仔细一想, 里面其实有重复计算的问题. 假设下面还有一层, 8 9 10 11 12 13. 在计算 4 5 的时候, 会把(8,9), (9,10), (10,11)连上, 在计算5, 6的时候,又会尝试(10,11), (11,12), (12,13), 这时候(10,11)就明显重复计算了. 如果我是面试官, 对于这种算法, 我肯定challenge 面试者. 第三题 这两道题虽然都解出来了,但是都有明显缺陷,虽然这里可能只是说举例思路,但还是不太恰当,希望能多注重算法效率. |
Beta Was this translation helpful? Give feedback.
-
第 114 题「将二叉树展开为链表」 好像遍历也是可以的? 创建一个指针就可以了. class Solution {
}; |
Beta Was this translation helpful? Give feedback.
-
第二题填充右侧节点,可以直接利用父节点的next指针: typedef struct Node node;
struct Node* connect(struct Node* root) {
if(root==NULL){
return NULL;
}
//root->next=NULL; //初始状态下,所有 next 指针都已经被设置为 NULL。
//不是叶节点
if(root->left!=NULL){
root->left->next=root->right;
//根节点不在三角形的边上
if(root->next!=NULL){
root->right->next=root->next->left;
}
// else{
// root->right->next=NULL;
// }
}
connect(root->left);
connect(root->right);
return root;
} |
Beta Was this translation helpful? Give feedback.
-
东哥,请问第三题的时间复杂度要怎么算呢?谢谢 |
Beta Was this translation helpful? Give feedback.
-
借鉴@Infinite-Unexpired-Love 116题的C语言解法,提供一个java版本:
|
Beta Was this translation helpful? Give feedback.
-
填充节点的右侧指针这一题感觉一眼队列bfs class Solution
{
public:
Node* connect(Node* root)
{
if (!root)
return root;
queue<Node*> q;
q.push(root);
while (!q.empty())
{
int sz = q.size();
for (int i = 0; i < sz; i++)
{
Node *cur = q.front();
q.pop();
if (i < sz - 1)
cur->next = q.front();
if (cur->left)
q.push(cur->left);
if (cur->right)
q.push(cur->right);
}
}
return root;
}
}; |
Beta Was this translation helpful? Give feedback.
-
114题:展开二叉树为链表。 class Solution {
public:
// 定义:将以 root 为根的二叉树展成单链表,返回单链表的头指针
TreeNode* func(TreeNode* root) {
if (root == nullptr) return root;
// 将左子树展开成单链表
TreeNode* left = func(root->left);
// 将右子树展开成单链表
TreeNode* right = func(root->right);
// 将 root 的左子树变为右子树
root->left = nullptr;
root->right = left;
// 将 root 原本的右子树挂到新的右子树上
TreeNode* p = root;
while (p->right) p = p->right;
p->right = right;
return root;
}
void flatten(TreeNode* root) {
func(root);
}
}; |
Beta Was this translation helpful? Give feedback.
-
116题感觉用层次遍历也能解:
|
Beta Was this translation helpful? Give feedback.
-
链表展开那题,维护一个last指针,先序在它的后面挂节点(应该属于遍历的思路?) class Solution {
private:
TreeNode* last = new TreeNode();
public:
void flatten(TreeNode* root) {
if (root == nullptr) return;
last->right = root;
last = last->right;
TreeNode *tmp_right = root->right;
flatten(root->left);
flatten(tmp_right);
root->left = nullptr;
}
}; |
Beta Was this translation helpful? Give feedback.
-
114 Flatten Binary Tree to Linked List
|
Beta Was this translation helpful? Give feedback.
-
文章链接点这里:东哥带你刷二叉树(思路篇)
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions