记录剑指Offer中二叉树
相关的题目思路及解答。
文章会给出思路和代码,同时为了方便本地调试,还会提供相应的测试用例。
如果要在本地调试,需要先包含下面的头文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #ifndef MY_TREE_NODE #define MY_TREE_NODE
#include <iostream>
using namespace std;
struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} };
void printTree(TreeNode *pNode) { if (pNode != NULL) { cout << "node: " << pNode->val << endl; if (pNode->left != NULL) cout << "left: " << pNode->left->val << " "; else cout << "left: NULL "; if (pNode->right != NULL) cout << "right: " << pNode->right->val << endl; else cout << "right: NULL" << endl; } if (pNode->left != NULL) { printTree(pNode->left); } if (pNode->right != NULL) { printTree(pNode->right); } }
#endif
|
剑指Offer7:重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
1 2 3 4 5 6 7 8 9
| 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3 / \ 9 20 / \ 15 7
|
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) { if (preorder.size() == 0 || inorder.size() == 0) return NULL; vector<int> preorder_left, preorder_right; vector<int> inorder_left, inorder_right; TreeNode *root = new TreeNode(preorder[0]);
int pos; for (pos = 0; pos < inorder.size(); pos++) { if (inorder[pos] == preorder[0]) break; inorder_left.push_back(inorder[pos]); } for (pos = pos + 1; pos < inorder.size(); pos++) inorder_right.push_back(inorder[pos]);
for (int i = 1; i < preorder.size(); i++) { if (i <= inorder_left.size()) preorder_left.push_back(preorder[i]); else preorder_right.push_back(preorder[i]); } root->left = buildTree(preorder_left, inorder_left); root->right = buildTree(preorder_right, inorder_right); return root; }
|
测试用例
1 2 3 4 5 6 7
| int main(int argc, char **argv) { vector<int> pre_vec = {3, 9, 20, 15, 7}; vector<int> in_vec = {9, 3, 15, 20, 7}; TreeNode *tree = buildTree(pre_vec, in_vec); printTree(tree); }
|
剑指Offer8:二叉树的下一个结点
题目:给定一棵二叉树和其中的一个结点,如何找出中序遍历顺序的下一个节点?
树中的结点除了有两个分别指向左右子结点的指针以外,还有一个指向父结点的指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct BinaryTreeNode { int value; BinaryTreeNode *left; BinaryTreeNode *right; BinaryTreeNode *parent; BinaryTreeNode(int x) : value(x), left(NULL), right(NULL), parent(NULL) {} };
void connectTree(BinaryTreeNode *parent, BinaryTreeNode *left, BinaryTreeNode *right) { parent->left = left; parent->right = right; left->parent = parent; right->parent = parent; }
|
思路:中序遍历
左递归->打印->右递归存在3种情况:
- 打印该节点之后,存在右子节点,进入右递归,接下来打印的是右递归子树的最左节点
- 打印该节点之后,不存在右子节点,且该节点是父节点的左节点,接下来打印这个节点的父节点(用入栈出栈理解递归)
- 打印该节点之后,不存在右子节点,且该节点是父节点的右节点,需要回溯父节点,直到找到一个左子节点,返回这个左子节点的父节点
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| BinaryTreeNode *getNext(BinaryTreeNode *node) { if (node == NULL) return NULL; BinaryTreeNode *res = NULL; if (node->right != NULL) { BinaryTreeNode *rightTree = node->right; while (rightTree->left != NULL) { rightTree = rightTree->left; } res = rightTree; } else { BinaryTreeNode *current = node; BinaryTreeNode *parent = node->parent; while (parent != NULL) { if (parent->left == current) { res = parent; break; } current = parent; parent = parent->parent; if (parent != NULL) { break; } if (current == parent->left && parent != NULL) { res = current->parent; break; } } } return res; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| int main(int argc, char **argv) { BinaryTreeNode *node3 = new BinaryTreeNode(3); BinaryTreeNode *node9 = new BinaryTreeNode(9); BinaryTreeNode *node20 = new BinaryTreeNode(20); BinaryTreeNode *node15 = new BinaryTreeNode(15); BinaryTreeNode *node7 = new BinaryTreeNode(7); connectTree(node3, node9, node20); connectTree(node20, node15, node7); BinaryTreeNode *next = NULL; next = getNext(node9); cout << next->value << endl; next = getNext(node3); cout << next->value << endl; next = getNext(node15); cout << next->value << endl; next = getNext(node20); cout << next->value << endl; next = getNext(node7); if (next == NULL) { cout << "NULL" << endl; } else { cout << next->value << endl; } }
|
剑指Offer26:树的子结构
题目:输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
思路:
- 对A遍历,找到A中和B的根节点value相同的节点RA
- 判断以RA为根节点的子树是否和B相同
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| bool isBinA(TreeNode *A, TreeNode *B);
bool isSubStructure(TreeNode *A, TreeNode *B) { bool res = false; if (A == NULL || B == NULL) { return false; } if (A->val == B->val) { res = isBinA(A, B); } if (!res) { res = isSubStructure(A->left, B); } if (!res) { res = isSubStructure(A->right, B); } return res; }
bool isBinA(TreeNode *A, TreeNode *B) { if (B == NULL) { return true; } if (A == NULL) { return false; } if (A->val != B->val) { return false; } return isBinA(A->left, B->left) && isBinA(A->right, B->right); }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| int main(int argc, char **agrv) { TreeNode *TNode3 = new TreeNode(3); TreeNode *TNode4 = new TreeNode(4); TreeNode *TNode5 = new TreeNode(5); TreeNode *TNode1 = new TreeNode(1); TreeNode *TNode2 = new TreeNode(2); TNode3->left = TNode4; TNode3->right = TNode5; TNode4->left = TNode1; TNode4->right = TNode2; TreeNode *TNodeB4 = new TreeNode(4); TreeNode *TNodeB1 = new TreeNode(1); TNodeB4->left = TNodeB1;
if (isSubStructure(TNode3, TNodeB4)) { cout << "True" << endl; } }
|
剑指Offer27:二叉树的镜像
题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。
思路:前序遍历,当遍历到的节点存在子节点时,交换子节点
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| TreeNode *mirrorTree(TreeNode *root) { if (root != NULL) { swap(root->left, root->right); } else { return NULL; } mirrorTree(root->left); mirrorTree(root->right); return root; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int main(int argc, char **argv) { TreeNode *node4 = new TreeNode(4); TreeNode *node2 = new TreeNode(2); TreeNode *node7 = new TreeNode(7); TreeNode *node1 = new TreeNode(1); TreeNode *node3 = new TreeNode(3); TreeNode *node6 = new TreeNode(6); TreeNode *node9 = new TreeNode(9); node4->left = node2; node4->right = node7; node2->left = node1; node2->right = node3; node7->left = node6; node7->right = node9; cout << "镜像前:" << endl; printTree(node4); cout << "镜像后:" << endl; TreeNode *mirror = mirrorTree(node4); printTree(mirror); }
|
剑指Offer28:对称的二叉树
题目:请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
思路:自顶向下递归,比较左右一对节点是否相同
递归终止条件:
- 左右同时没有子节点,对称
- 有左无右或者有右无左,不对称
- 左右值不相同,不对称
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| bool judge(TreeNode *left, TreeNode *right) { if (!left && !right) return true; if (!left || !right) return false; if (left->val != right->val) return false; return judge(left->left, right->right) && judge(left->right, right->left); }
bool isSymmetric(TreeNode *root) { if (!root) { return true; } return judge(root->left, root->right); }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main(int argc, char **argv) { TreeNode *root = new TreeNode(1); TreeNode *l2 = new TreeNode(2); TreeNode *r2 = new TreeNode(2); TreeNode *l3 = new TreeNode(3); TreeNode *r3 = new TreeNode(3); root->left = l2; root->right = r2; l2->right = l3; r2->right = r3; isSymmetric(root) ? cout << "对称的" << endl : cout << "不对称" << endl; }
|
剑指Offer32(一):不分行从上往下打印二叉树
题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印
思路:层序遍历
二叉树的前/中/后遍历可以递归实现,即使用栈结构
层序遍历无法递归,用队列实现
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| vector<int> levelOrder(TreeNode *root) { if (root == NULL) { return {}; } deque<TreeNode *> deq; vector<int> res; deq.push_back(root); while (!deq.empty()) { TreeNode *node = deq.front(); res.push_back(node->val); if (node->left) { deq.push_back(node->left); } if (node->right) { deq.push_back(node->right); } deq.pop_front(); } return res; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int main(int argc, char **argv) { TreeNode *node3 = new TreeNode(3); TreeNode *node9 = new TreeNode(9); TreeNode *node20 = new TreeNode(20); TreeNode *node15 = new TreeNode(15); TreeNode *node7 = new TreeNode(7); node3->left = node9; node3->right = node20; node20->left = node15; node20->right = node7; vector<int> res = levelOrder(node3); for (int i = 0; i < res.size(); i++) { cout << res[i] << " "; } cout << endl; }
|
剑指Offer32(二):分行从上到下打印二叉树
题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。
思路:和32_1相比,只需要添加两个变量
一个记录当前层等待输出的个数cur,另一个记录下一层的个数next
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| vector<vector<int>> levelOrder(TreeNode *root) { if (root == NULL) { return {}; } deque<TreeNode *> deq; vector<vector<int>> res; vector<int> res_level; deq.push_back(root); int cur = 1; int next = 0; while (!deq.empty()) { TreeNode *node = deq.front(); res_level.push_back(node->val); if (node->left) { deq.push_back(node->left); next++; } if (node->right) { deq.push_back(node->right); next++; } deq.pop_front(); cur--; if (cur == 0) { res.push_back(res_level); res_level.clear(); cur = next; next = 0; } } return res; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| int main(int argc, char **argv) { TreeNode *node3 = new TreeNode(3); TreeNode *node9 = new TreeNode(9); TreeNode *node20 = new TreeNode(20); TreeNode *node15 = new TreeNode(15); TreeNode *node7 = new TreeNode(7); node3->left = node9; node3->right = node20; node20->left = node15; node20->right = node7; vector<vector<int>> res = levelOrder(node3); for (int i = 0; i < res.size(); i++) { for (int j = 0; j < res[i].size(); j++) { cout << res[i][j] << " "; } cout << endl; } cout << endl; }
|
剑指Offer32(三):之字形打印二叉树
题目:请实现一个函数按照之字形顺序打印二叉树
即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
思路1:利用双向队列
- 在32_2基础上,添加奇偶标志位
- 奇数层,从左至右输出,所以前取后放
- 偶数层,从右至左输出,所以后取前放
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| vector<vector<int>> levelOrder(TreeNode *root) { if (root == NULL) { return {}; } deque<TreeNode *> deq; vector<vector<int>> res; vector<int> res_level; bool isOdd = true; TreeNode *node; deq.push_back(root); int cur = 1; int next = 0; while (!deq.empty()) { if (isOdd) { node = deq.front(); res_level.push_back(node->val); deq.pop_front(); cur--; if (node->left) { deq.push_back(node->left); next++; } if (node->right) { deq.push_back(node->right); next++; } } else { node = deq.back(); res_level.push_back(node->val); deq.pop_back(); cur--; if (node->right) { deq.push_front(node->right); next++; } if (node->left) { deq.push_front(node->left); next++; } } if (cur == 0) { res.push_back(res_level); res_level.clear(); isOdd = !isOdd; cur = next; next = 0; } } return res; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| int main(int argc, char **argv) { TreeNode *node1 = new TreeNode(1); TreeNode *node2 = new TreeNode(2); node1->left = node2; vector<vector<int>> res = levelOrder(node1); for (int i = 0; i < res.size(); i++) { for (int j = 0; j < res[i].size(); j++) { cout << res[i][j] << " "; } cout << endl; } }
|
剑指Offer33:二叉搜索树的后序遍历序列
题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。
思路:
BST的后序遍历满足两个条件:
- 左子树<根<右子树
- 最后一个数字是根节点
- 找到左右子树的序列,并递归检查左右子树是不是后序遍历序列
递归终止条件:序列的左右断点重合,即无法再分出子树
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| bool recursion(vector<int> &vec, int left, int right);
bool verifyPostorder(vector<int> &postorder) { return recursion(postorder, 0, postorder.size() - 1); }
bool recursion(vector<int> &vec, int left, int right) { if (left >= right) return true; int root = vec[right]; int divide = left; for (; divide < right; divide++) { if (vec[divide] > root) break; } for (int j = divide; j < right; j++) { /这里不是j < right-1* if (vec[j] < root) return false; } return recursion(vec, left, divide - 1) && recursion(vec, divide, right - 1); }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| int main(int argc, char **argv) { vector<int> in1 = {1, 6, 3, 2, 5}; if (verifyPostorder(in1)) { cout << "true" << endl; } else { cout << "false" << endl; } vector<int> in2 = {1, 2, 5, 10, 6, 9, 4, 3}; if (verifyPostorder(in2)) { cout << "true" << endl; } else { cout << "false" << endl; } }
|
剑指Offer34:二叉树中和为某一值的路径
题目:输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。
从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
思路:前序遍历+回溯
当遍历到叶子节点后,检查当前路径的长度
一层递归结束后,需要弹出path末端的节点
递归终点:到左右子节点为空
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void recursion(TreeNode* root, int& sum, vector<vector<int>>& res, vector<int>& path, int& p_sum) { path.push_back(root->val); if (root->left == NULL && root->right == NULL) { for (int i = 0;i < path.size();i++) { p_sum += path[i]; } if (p_sum == sum) { res.push_back(path); } p_sum = 0; } if (root->left) recursion(root->left, sum, res, path, p_sum); if (root->right) recursion(root->right, sum, res, path, p_sum); path.pop_back(); }
vector<vector<int>> pathSum(TreeNode* root, int sum) { if (root == NULL) { return {}; } vector<vector<int>> res; vector<int> path; int p_sum = 0; recursion(root, sum, res, path, p_sum); return res; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| int main(int argc, char** argv) { TreeNode* n5 = new TreeNode(5); TreeNode* n4 = new TreeNode(4); TreeNode* n8 = new TreeNode(8); TreeNode* n11 = new TreeNode(11); TreeNode* n13 = new TreeNode(13); TreeNode* n4_ = new TreeNode(4); TreeNode* n7 = new TreeNode(7); TreeNode* n2 = new TreeNode(2); TreeNode* n5_ = new TreeNode(5); TreeNode* n1 = new TreeNode(1); n5->left = n4; n5->right = n8; n4->left = n11; n8->left = n13; n8->right = n4_; n11->left = n7; n11->right = n2; n4_->left = n5_; n4_->right = n1; vector<vector<int>> res = pathSum(n5, 22); for (int i = 0;i < res.size();i++) { for (int j = 0;j < res[i].size();j++) { cout << res[i][j] << " "; } cout << endl; } }
|
剑指Offer36:二叉搜索树与双向链表
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求
不能创建任何新的结点,只能调整树中结点指针的指向。
思路:
- 本题目需要返回的是循环双向队列
2。 BST的中序遍历就是递增序列
- 先定义head和tail指针,head指向左递归的终点,tail随着递归的回溯向后移动
- 最后将头尾连接起来,实现循环
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| Node *head, *tail = NULL;
void dfs(Node *root) { if (!root) return; dfs(root->left); if (!tail) { head = root; } else { tail->right = root; root->left = tail; } tail = root; dfs(root->right); }
Node *treeToDoublyList(Node *root) { if (!root) return NULL; dfs(root); head->left = tail; tail->right = head; return head; }
|
测试用例
1 2 3 4 5 6 7 8 9 10
| int main(int argc, char **argv) { Node *n1 = new Node(1); Node *n3 = new Node(3); Node *n2 = new Node(2, n1, n3); Node *n5 = new Node(5); Node *n4 = new Node(4, n2, n5); Node *list = treeToDoublyList(n4); cout << list->val << " left: " << list->left->val << " right: " << list->right->val << endl; }
|
剑指Offer37. 序列化二叉树
题目:请实现两个函数,分别用来序列化和反序列化二叉树。
说明: 不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。
思路:
序列化的方式和书上不一样,书上是前序遍历,LeetCode上面是层序遍历。其实根据题目意思,只要反序列化后能和之前一样,就没问题
关于层序遍历,可以先看LeetCode102,要用到BFS广度优先遍历
注意:这里末尾输出会包含很多null,即叶子节点的子节点,但是只要能够反序列化成原始的状态,就能通过测试
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| string serialize(TreeNode *root) { if (!root) return ""; ostringstream res; queue<TreeNode *> bfs; bfs.push(root); while (!bfs.empty()) { TreeNode *node = bfs.front(); bfs.pop(); if (node != NULL) { bfs.push(node->left); bfs.push(node->right); res << node->val << ','; } else { res << "null,"; } } return res.str(); }
TreeNode *deserialize(string data) { if (data.empty()) { return NULL; } istringstream node_steam(data); string node; vector<TreeNode *> res; while (getline( node_steam, node, ',')) { if (node == "null") { res.push_back(NULL); } else { res.push_back(new TreeNode(stoi(node))); } } int j = 1; for (int i = 0; j < res.size(); i++) { if (!res[i]) { continue; } res[i]->left = res[j++]; if (j < res.size()) { res[i]->right = res[j++]; } } return res[0]; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int main(int argc, char **argv) { TreeNode *n1 = new TreeNode(1); TreeNode *n2 = new TreeNode(2); TreeNode *n3 = new TreeNode(3); TreeNode *n4 = new TreeNode(4); TreeNode *n5 = new TreeNode(5); n1->left = n2; n1->right = n3; n3->left = n4; n3->right = n5; cout << "原树: " << endl; printTree(n1); string out = serialize(n1); cout << "序列化后:" << out << '\n' << "反序列化后:" << endl; printTree(deserialize(out)); }
|
剑指Offer54:二叉搜索树的第k个结点
题目:给定一棵二叉搜索树,请找出其中的第k大的结点。
思路:
二叉搜索树的中序遍历就是一个递增的数组
这道题目需要构建一个递减的数组找到第k大的数字,因此采用右-中-左的顺序
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int count = 0, res = 0;
void helper(TreeNode *node, int k) { if (!node) return; helper(node->right, k); ++count; if (count == k) { res = node->val; return; } helper(node->left, k); }
int kthLargest(TreeNode *root, int k) { helper(root, k); return res; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12
| int main() { TreeNode *root = new TreeNode(3); TreeNode *node1 = new TreeNode(1); TreeNode *node4 = new TreeNode(4); TreeNode *node2 = new TreeNode(2); root->left = node1; root->right = node4; node1->right = node2; printTree(root); cout << kthLargest(root, 1) << endl; }
|
剑指Offer55(一):二叉树的深度
题目:输入一棵二叉树的根结点,求该树的深度。
从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
思路1:层序遍历
和剑指32一样的,对二叉树做一个层序遍历
不同的是用到了两个队列,一个记录当前层节点,另一个记录下一层节点
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| int maxDepth(TreeNode *root) { if (!root) return 0; queue<TreeNode *> cur; cur.push(root); int cnt = 0; while (!cur.empty()) { queue<TreeNode *> next; while (!cur.empty()) { if (cur.front()->left) next.push(cur.front()->left); if (cur.front()->right) next.push(cur.front()->right); cur.pop(); } cur = next; ++cnt; } return cnt; }
|
思路2:DFS后序遍历
找到左子树以及右子树的深度,两者中大的值+1(root)返回
基础的后序遍历返回值是void,这里返回的是深度值,可以理解为函数调用的次数
show me code
1 2 3 4 5 6
| int maxDepth(TreeNode *root) { if (!root) return 0; return max(maxDepth(root->left), maxDepth(root->right)) + 1; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main(int argc, char **argv) { TreeNode *n3 = new TreeNode(3); TreeNode *n9 = new TreeNode(9); TreeNode *n20 = new TreeNode(20); TreeNode *n15 = new TreeNode(15); TreeNode *n7 = new TreeNode(7); n3->left = n9; n3->right = n20; n20->left = n15; n20->right = n7; cout << maxDepth(n3) << endl; }
|
剑指Offer55(二):平衡二叉树
题目:输入一棵二叉树的根结点,判断该树是不是平衡二叉树。
如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
思路1:
用55_1_maxDepth的思路,分别找出左子树和右子树的深度
判断是不是两者差<=1
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int depth(TreeNode *node) { if (!node) return 0; return max(depth(node->left), depth(node->right)) + 1; }
bool isBalanced(TreeNode *root) { if (!root) return true; bool res = abs(depth(root->left) - depth(root->right)) <= 1; return res && isBalanced(root->left) && isBalanced(root->right); }
|
思路2:后序遍历+剪枝
对二叉树做一个后序遍历,从底向上返回深度,当子树不平衡的话就剪枝直接向上返回
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int dfs(TreeNode *root) { if (!root) return 0; int left = dfs(root->left); if (left == -1) return -1; int right = dfs(root->right); if (right == -1) return -1; return abs(left - right) < 2 ? max(left, right) + 1 : -1; } bool isBalanced(TreeNode *root) { return dfs(root) != -1; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int main(int argc, char **agrv) { TreeNode *n3 = new TreeNode(3); TreeNode *n9 = new TreeNode(9); TreeNode *n20 = new TreeNode(20); TreeNode *n15 = new TreeNode(15); TreeNode *n7 = new TreeNode(7); n3->left = n9; n3->right = n20; n20->left = n15; n20->right = n7;
if (isBalanced(n3)) cout << "true" << endl; else cout << "false" << endl; }
|
剑指Offer68-1:二叉搜索树的最近公共祖先
题目:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
思路1:两次遍历找到路径
对于输入的两个节点,两次遍历得到从根节点到两个节点的路径
由于是二叉搜索树,因此可以通过比对大小确定路径
最后输出两个路径上共同的点
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| vector<TreeNode *> getPath(TreeNode *root, TreeNode *target) { vector<TreeNode *> path; TreeNode *node = root; while (node != target) { path.push_back(node); if (target->val < node->val) node = node->left; else node = node->right; } path.push_back(node); return path; } TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) { vector<TreeNode *> path_p = getPath(root, p); vector<TreeNode *> path_q = getPath(root, q); TreeNode *ancestor; for (int i = 0; i < path_p.size() && i < path_q.size(); ++i) { if (path_p[i] == path_q[i]) ancestor = path_p[i]; else break; } return ancestor; }
|
思路2:一次遍历
- p,q都在root左子树,root遍历至左节点
- p,q都在root右子树,root遍历至右节点
- p,q分别在root的左右两边,说明找到了祖先节点
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13
| TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) { while (root) { if (p->val < root->val && q->val < root->val) root = root->left; else if (p->val > root->val && q->val > root->val) root = root->right; else break; } return root; }
|
思路3:递归
show me code
1 2 3 4 5 6 7 8
| TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) { if (p->val < root->val && q->val < root->val) return lowestCommonAncestor(root->left, p, q); if (p->val > root->val && q->val > root->val) return lowestCommonAncestor(root->right, p, q); return root; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int main() { TreeNode *n6 = new TreeNode(6); TreeNode *n2 = new TreeNode(2); TreeNode *n8 = new TreeNode(8); TreeNode *n0 = new TreeNode(0); TreeNode *n4 = new TreeNode(4); TreeNode *n7 = new TreeNode(7); TreeNode *n9 = new TreeNode(9); TreeNode *n3 = new TreeNode(3); TreeNode *n5 = new TreeNode(5); n6->left = n2; n6->right = n8; n2->left = n0; n2->right = n4; n8->left = n7; n8->right = n9; n4->left = n3; n4->right = n5; cout << lowestCommonAncestor(n6, n2, n4)->val << endl; }
|
剑指Offer68-2:二叉树的最近公共祖先
题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
思路:递归
- 在root的左子树递归查找p,q
- 在root的右子树递归查找p,q
- p,q的分布存在四种情况
- 左右都不在,返回nullptr
- 左边和右边都存在,返回root
- 只在左边找到了,返回root->left
- 只在右边找到了,返回root->right
show me code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) { if (!root || !p || !q || p == root || q == root) return root; TreeNode *left = lowestCommonAncestor(root->left, p, q); TreeNode *right = lowestCommonAncestor(root->right, p, q); if (!left && !right) return nullptr; if (left && !right) return left; if (!left && right) return right; else return root; }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int main() { TreeNode *n3 = new TreeNode(3); TreeNode *n5 = new TreeNode(5); TreeNode *n1 = new TreeNode(1); TreeNode *n6 = new TreeNode(6); TreeNode *n2 = new TreeNode(2); TreeNode *n0 = new TreeNode(0); TreeNode *n8 = new TreeNode(8); TreeNode *n7 = new TreeNode(7); TreeNode *n4 = new TreeNode(4); n3->left = n5; n3->right = n1; n5->left = n6; n5->right = n2; n1->left = n0; n1->right = n8; n2->left = n7; n2->right = n4; cout << lowestCommonAncestor(n3, n5, n4)->val << endl; }
|