- 中序遍历二叉树
- 递归做法
void inorderTraversalBase(TreeNode* root, vector<int>& res){ if(root == NULL) return; inorderTraversalBase(root->left, res); res.push_back(root->val); inorderTraversalBase(root->right, res); } vector<int> inorderTraversal(TreeNode* root) { vector<int> res; inorderTraversalBase(root, res); return res; }
- 非递归做法, 利用栈现将左节点存起来。前序也可以基于这个framework去修改。将加入数组的操作放在while(root) 内即可。
vector<int> inorderTraversalIterating(TreeNode* root){ stack<TreeNode* > stack1; vector<int> res; while(root != NULL || !stack1.empty()){ while(root){ stack1.push(root); root = root->left; } // 没有左孩子,则当前节点就应该加入队列中。 root = stack1.top(); res.push_back(root->val); stack1.pop(); root = root->right; } return res; }
- 二叉树层次序遍历
- 每一层对应一个vector, 最终返回一个vector<vector<>>类型的数据。
- 层次序遍历还是使用queue。
- 关键在于如何计算每层的节点个数。我们利用nums计数当前level的总节点的个数。用next_level_num计算下一层的个数。nums初始化为1.
- 当当前节点不为null的时候意味着下一层有两个节点(NULL也算一个),所以next_level_nums +=2
- 当已经遍历完本层节点后,则开始遍历下一层节点.
vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> res; vector<int> cur_level; int nums = 1; int count = 0; queue<TreeNode*> nodes; nodes.push(root); int next_levels_num = 0; while(!nodes.empty()){ TreeNode* cur_node = nodes.front(); nodes.pop(); if(cur_node != NULL){ nodes.push(cur_node->left); nodes.push(cur_node->right); cur_level.push_back(cur_node->val); next_levels_num += 2; } count += 1; if(count == nums){ nums = next_levels_num; next_levels_num = 0; count = 0; res.push_back(cur_level); cur_level = {}; } } return res; }
- 由前序和中序序列构建二叉树
- 前提是输入合法并且没有重复的元素
- 首先利用前序的第一个节点构建一个node, 并根据这个数,将中序,前序序列分为前段后后段。
- node的左孩子就是根据前段构造的子树。
- node的右孩子就是根据后段构造的子树。
- 通过递归的方式来完成整个树的构造。
TreeNode* buildTreeBase(vector<int>& preorder, vector<int>& inorder, int l_pre, int r_pre, int l_in, int r_in){ if(l_pre > r_pre || l_in > r_in){ return NULL; } int root_value = preorder[l_pre]; TreeNode* root = new TreeNode(root_value); int target_l_in = -1; for(int i=l_in; i<=r_in;i++){ if(inorder[i] == root_value){ target_l_in = i; break; } } int num_nodes_left = target_l_in - l_in; root->left = buildTreeBase(preorder, inorder, l_pre + 1, l_pre + num_nodes_left ,l_in, target_l_in-1); root->right = buildTreeBase(preorder, inorder, l_pre + num_nodes_left + 1, r_pre, target_l_in + 1, r_in); return root; } TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { if(preorder.size() != inorder.size()) return NULL; int size = (int) preorder.size(); return buildTreeBase(preorder, inorder, 0, size-1, 0, size-1); }
- 将一颗二叉树转化成一个链表
- 将二叉树按照前序遍历的方式转化成一个链表,左孩子都是空,只使用右孩子代表next。
- 解法1:利用辅助存储空间
- 我们首先对二叉树进去前序遍历
- 按照顺序保存前序遍历的节点。
- 再遍历所有节点,right = next,left= NULL
- 解法2: 不利用存储空间。
- 因为我们是按照前序序列构建列表,所以我们可以构造一种新的遍历方式。
- 先遍历左孩子,再右孩子,再自身节点。
- 通过上面的递归遍历,我们访问得到的第一个节点就是我们链表中的最后一个节点。访问的最后一个节点就是我们链表中的第一个节点。
- 针对访问过程中的每个节点,我们保存上一个其访问的节点X。则当前节点的right= X,left=NULL, X=current.
- 等遍历完成了,则链表也构造完成。
- 代码:
void flatten(TreeNode* root) { vector<TreeNode*> nodes; stack<TreeNode*> stack1; TreeNode* cur = root; while(cur != NULL || !stack1.empty()){ while (cur){ stack1.push(cur); nodes.push_back(cur); cur = cur->left; } cur = stack1.top(); stack1.pop(); cur = cur->right; } cur = root; for(int i=1;i<nodes.size();i++){ cur->right = nodes[i]; cur->left = NULL; cur = cur->right; } cur->right = NULL; } TreeNode* prev = NULL; void flattenV2(TreeNode* root){ if(root == NULL) return; flattenV2(root->right); flattenV2(root->left); root->right = prev; root->left = NULL; prev = root; }
- 计算二叉树的深度:
- 思路:利用递归的方式,depth= max(MAXDEPTH(root->left)+1, MAXDEPTH(root->right) + 1);
- 代码:
int maxDepthBase(TreeNode* root, int height){ if(root == NULL){ return height; } return max(maxDepthBase(root->left, height + 1), maxDepthBase(root->right, height + 1)); } int maxDepth(TreeNode* root) { return maxDepthBase(root, 0); }
- 判断一颗二叉树是否是镜像二叉树。
- 利用递归的思想。
- 首先我们定义一种新的遍历方式A:先遍历右节点,再遍历左节点,再是根节点。
- 如果一棵树是镜像二叉树,那么他前序访问得到的value和A访问得到的value是一致的,则是镜像二叉树。
- 所以我们只写一个i递归,同时进行两种遍历,判断每一刻他们节点的值是否相同,如果一致相同则是镜像二叉树。
- 代码:
bool isSymmetricBase(TreeNode* root1, TreeNode* root2){ if(root1 == NULL && root2 == NULL) return true; if(root1 == NULL || root2 == NULL) return false; return (root1->val == root2->val) && isSymmetricBase(root1->left, root2->right) && isSymmetricBase(root1->right, root2->left); } bool isSymmetric(TreeNode* root) { return isSymmetricBase(root, root); }
- 有多少种不同的二叉搜素树。
- 如果一个N,代表节点的个数,试计算一共有多少种不同的二叉搜素树。
- 如果N=1,则有一种方式。
- 如果N=2,我们选取根节点有两种方式,每种对应的一种解决方案。因为另一个要么是在根节点的左边,要么是在跟节点的右边。2=1+1
- 如果N=3,我们选取跟节点有三种方式,当根节点=1,右子树个数为0,左子树节点个数为2(两种构造方式)。当跟节点=2,左右各1,当跟节点为3,右子树为2,左子树为0.所以Res=2+1+2=5
- 所以我们可以总结如下规律: f ( n ) = ∑ i = 1 n f ( i − 1 ) ∗ f ( n − i ) f(n) = \sum_{i=1}^nf(i-1)*f(n-i) f(n)=∑i=1nf(i−1)∗f(n−i)。
- 代码:
int numTrees(int n) { int counts[n+1]; counts[0] = 1; counts[1] = 1; counts[2] = 2; if(n<=2) return counts[n]; for(int i=3;i<=n;i++){ int count = 0; // 一共是i个点 for(int j=0;j<i;j++){ // 选取第j点作为根节点 count += (counts[j] * counts[i-j-1]); } counts[i] = count; } return counts[n]; }
- 判断一颗二叉树是不是二叉搜索树。
- 利用的递归的思想。
- 一开始的取值范围是[Null, null]
- 在中序遍历的过程中不停的更新范围
- 判断节点的值是否在该范围中,如果在,继续,如果不在,则可以返回false。
- 代码:
bool isValidBSTBase(TreeNode* root, int* min_val, int* max_val){ if(root == NULL) return true; if(min_val != NULL && (*min_val) >= root->val) return false; if(max_val != NULL && (*max_val) <= root->val) return false; return isValidBSTBase(root->left, min_val, &root->val) && isValidBSTBase(root->right, &root->val, max_val); } bool isValidBST(TreeNode* root) { return isValidBSTBase(root, NULL, NULL); }
[leetcode] 二叉树相关题目
最新推荐文章于 2024-05-15 15:47:18 发布