东哥带你刷二叉树(思路篇) :: 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.
-
东哥牛逼! |
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.
-
hhy必进大厂 |
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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:东哥带你刷二叉树(思路篇)
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions