树相关
1.重建二叉树
1 class Solution { 2 public: 3 TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { 4 if(pre.size() == 0 || vin.size() == 0) 5 return nullptr; 6 return constructCore(pre, vin, 0, pre.size()-1, 0, vin.size()-1); 7 } 8 9 TreeNode* constructCore(vector<int> pre,vector<int> vin, int sp, int ep, int si, int ei) 10 { 11 //sp, ep 确定先序中树的范围,si,ei确定中序的子树范围 12 //先序头就是根 13 int rootValue = pre[sp]; 14 TreeNode* root = new TreeNode(rootValue); 15 if(sp == ep) 16 { 17 if(si == ei && pre[sp] == vin[si]) 18 return root; 19 } 20 //中序找到根,分为左右子树 21 int index = si; 22 while(index <= ei && vin[index] != rootValue) 23 ++index; 24 int leftLen = index-si;//左子树长度 25 if(leftLen > 0) 26 { 27 root->left = constructCore(pre, vin, sp+1, sp+leftLen, si, index-1); 28 } 29 if(leftLen < ep-sp) 30 { 31 root->right = constructCore(pre, vin, sp+leftLen+1, ep, index+1, ei); 32 } 33 return root; 34 } 35 };
2.树的子结构
1 class Solution { 2 public: 3 bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) 4 { 5 //tree2空或者tree1空都不符合,问清楚空树是不是子树 6 if(pRoot2 == nullptr || pRoot1 == nullptr) 7 return false; 8 bool res = false; 9 if(pRoot1 != nullptr && pRoot2 != nullptr) 10 { 11 if(pRoot1->val == pRoot2->val)//找到匹配的根 12 res = isSubTree(pRoot1, pRoot2); 13 if(!res)//未找到,递归左节点 14 res = HasSubtree(pRoot1->left, pRoot2); 15 if(!res)//未找到,递归节点 16 res = HasSubtree(pRoot1->right, pRoot2); 17 } 18 return res; 19 } 20 //判断是否是子树 21 bool isSubTree(TreeNode* pRoot1, TreeNode* pRoot2) 22 { 23 //tree2先遍历结束,重合 24 if(pRoot2 == nullptr) 25 return true; 26 //主树先结束,不重合 27 if(pRoot1 == nullptr) 28 return false; 29 //对于节点值不等,不重合 30 if(pRoot1->val != pRoot2->val) 31 return false; 32 33 //节点值相等,递归判断左右子树 34 return isSubTree(pRoot1->left, pRoot2->left) 35 && isSubTree(pRoot1->right, pRoot2->right); 36 } 37 };
3.二叉树镜像
1 class Solution { 2 public: 3 void Mirror(TreeNode *pRoot) { 4 //前序遍历(根左右)树每个节点,如果节点有子节点,就交换子节点,直到叶子节点 5 //处理空树 6 if(pRoot == nullptr) 7 return; 8 //到达叶子节点 9 if(pRoot->left == nullptr && pRoot->right == nullptr) 10 return; 11 //交换子节点 12 TreeNode* tmp = pRoot->left; 13 pRoot->left = pRoot->right; 14 pRoot->right = tmp; 15 //递归左子树 16 if(pRoot->left) 17 Mirror(pRoot->left);//不要return,因为void不返回 18 19 //递归右子树 20 if(pRoot->right) 21 Mirror(pRoot->right); 22 } 23 };
4.对称二叉树
1 class Solution { 2 public: 3 bool isSymmetrical(TreeNode* pRoot) 4 { 5 return isSymmetrical(pRoot, pRoot); 6 } 7 8 bool isSymmetrical(TreeNode* pRoot1, TreeNode* pRoot2) 9 { 10 if(pRoot1 == nullptr && pRoot2 == nullptr)//都空,对称 11 return true; 12 if(pRoot1 == nullptr || pRoot2 == nullptr)//一空一不空。不对称 13 return false; 14 if(pRoot1->val != pRoot2->val)//都不空,值不等,不对称,写了return true就无法再往下遍历了 15 return false; 16 //都不空,且值相等,在比较下一个节点 17 return isSymmetrical(pRoot1->left, pRoot2->right) 18 && isSymmetrical(pRoot1->right, pRoot2->left); 19 } 20 };
5.二叉树前中后续遍历,递归和循环版
递归就是递归,循环实现用栈(前序中序比较简单,后续的话需要简单修改一下前序遍历,反转即可)
前序遍历非递归版
1 class Solution { 2 public: 3 vector<int> res; 4 vector<int> preorderTraversal(TreeNode *root) { 5 if(!root) 6 return {}; 7 stack<TreeNode*> s; 8 s.push(root); 9 while(!s.empty()) 10 { 11 auto p = s.top(); 12 s.pop(); 13 res.push_back(p->val); 14 if(p->right) 15 s.push(p->right); 16 if(p->left) 17 s.push(p->left); 18 } 19 return res; 20 } 21 };
6.后序遍历非递归版
1 class Solution { 2 public: 3 //一个巧妙地算法,先序遍历:根->左->右,根据出栈顺序根->右->左reverse,变成 左->右->根 4 vector<int> res; 5 vector<int> postorderTraversal(TreeNode *root) { 6 if(root == nullptr) 7 return {}; 8 stack<TreeNode*> s; 9 s.push(root); 10 while(!s.empty()) 11 { 12 auto p = s.top(); 13 s.pop(); 14 res.push_back(p->val); 15 if(p->left) 16 s.push(p->left); 17 if(p->right) 18 s.push(p->right); 19 } 20 reverse(res.begin(), res.end()); 21 return res; 22 } 23 };
7.二叉树中和为某值的路径
1 class Solution { 2 public: 3 vector<vector<int> > res; 4 //递归解决,防止段错误 5 vector<vector<int> > FindPath(TreeNode* root,int expectNumber) { 6 if(root == nullptr) 7 return res; 8 vector<int> cur; 9 find(root, expectNumber, cur); 10 return res; 11 } 12 13 void find(TreeNode* root, int target, vector<int> cur) 14 { 15 if(root == nullptr) 16 return ; 17 cur.push_back(root->val); 18 if((target-root->val) == 0 && root->left == nullptr && root->right == nullptr) 19 res.push_back(cur); 20 else 21 { 22 if(root->left) 23 find(root->left, target-root->val, cur); 24 if(root->right) 25 find(root->right, target-root->val, cur); 26 } 27 } 28 };
8.二叉树的深度
(递归)
1 class Solution { 2 public: 3 int res = 0; 4 int TreeDepth(TreeNode* pRoot) 5 { 6 int depth = 0; 7 getDepth(pRoot, depth); 8 return res; 9 } 10 11 //递归函数,每遇到null节点说明到底了,更新res 12 void getDepth(TreeNode* root, int depth) 13 { 14 if(root == nullptr) 15 { 16 res = (depth > res) ? depth : res; 17 return ; 18 } 19 else 20 { 21 getDepth(root->left, depth+1); 22 getDepth(root->right, depth+1); 23 } 24 } 25 };
非递归(使用队列BFS层序遍历 数层数)
class Solution { public: //非递归,使用BFS栈来解决问题,其中的打印内容可以辅助查看具体过程 int TreeDepth(TreeNode *pRoot) { if (pRoot == nullptr) return 0; queue<TreeNode *> s; s.push(pRoot); int depth = 0; while (!s.empty()) { depth++; int len = s.size(); cout << "第" << depth << "层,共有节点:" << len << "个" << endl; for (int i = 0; i < len; i++) { auto p = s.front(); s.pop(); cout << p->val << "出栈" << endl; if (p->left) { s.push(p->left); cout << p->left->val << "入栈" << endl; } if (p->right) { s.push(p->right); cout << p->right->val << "入栈" << endl; } } } return depth; } };
9.二叉树的最小深度(使用队列来实现,将上面一个算法简单改改即可:在第一次左右子节点都不存在时,跳出即可)
1 class Solution { 2 public: 3 //那我也用层序遍历(BFS)试试吧 4 int run1(TreeNode *root) { 5 if(root == nullptr) 6 return 0; 7 8 queue<TreeNode*> q; 9 q.push(root); 10 int depth = 0; 11 while(!q.empty()) 12 { 13 depth++; 14 int len = q.size(); 15 for(int i=0; i<len; i++) 16 { 17 auto p = q.front(); 18 q.pop(); 19 if(p->left == nullptr && p->right == nullptr) 20 return depth; 21 if(p->left) 22 q.push(p->left); 23 if(p->right) 24 q.push(p->right); 25 } 26 } 27 return depth; 28 } 29 //从上述方法我们可以想到,求算二叉树深度,也可以采用此法,跟我们原来的做法略有不同 30 31 //神奇的递归做法 32 int run(TreeNode *root) { 33 if(root == nullptr) 34 return 0; 35 int l = run(root->left); 36 int r = run(root->right); 37 if(l == 0 || r == 0) 38 return 1+l+r; 39 else 40 return 1+min(l, r); 41 } 42 };
序列化和反序列化二叉树