先把树中的左边界都放进栈,然后弹出,每弹出一个,判断是否有右边界,有的话压进栈,然后直到空弹出,周而复始
准备一个队列,头结点进,出了先放左再放右,弹出就打印
比较结束后,再循环外加一次比较,最后一层与max作比较
左树比父节点小,右树比父节点大
每一层是满的,不满的层也是从左到右变满
最大深度为:l;节点数为:n,满足n = 2**l-1
左树是平衡二叉树
右树是平衡二叉树
左树和右树的差的绝对值不大于2
序列化:将树转换为字符串的形式
反序列化:将字符串转换为树的形式
先回溯所有的节点,记录所有结点的父节点,然后放进哈希表,逐个遍历
让o2往上遍历,遇到第一个set1里有的,就是最低公共祖先
有可能情况:
中序遍历中节点的下一个节点
常规作法:中序遍历后生成一个序列,然后才知道后继节点,复杂度高
如果任何节点都有指向父节点的指针,复杂度变为需求的K,而不是N
当无右子树情况,while循环条件,父是空的情况为一直往上走,但是没有父节点,即没有后继节点,返回null,则该结点是最右端结点,否则当一直为右子树结点是,结点会往父节点移,父指针也会往上指,就是在不断的往上,直到成为父的左子树
class Solution {public: void preorder(vector<int> &res, TreeNode *root){ if(root == NULL) return; res.push_back(root->val); preorder(res, root->left); preorder(res, root->right); } vector<int> preorderTraversal(TreeNode* root) { // write code here vector<int> res; preorder(res, root); return res; }};
class Solution {public: vector<int> preorderTraversal(TreeNode* root) { vector<int> res; if(root == NULL) return res; //辅助栈 stack<TreeNode*> s; //根节点先进栈 s.push(root); //直到栈中没有节点 while(!s.empty()){ //每次栈顶就是访问的元素 TreeNode* node = s.top(); s.pop(); res.push_back(node->val); //如果右边还有右子节点进栈 if(node->right) s.push(node->right); //如果左边还有左子节点进栈 if(node->left) s.push(node->left); } return res; }};
两种的时间复杂度和空间复杂度都为O(N)
class Solution {public: void inorder(vector<int> &res, TreeNode *root){ if(root == NULL) return; inorder(res, root->left); res.push_back(root->val); inorder(res, root->right); } vector<int> inorderTraversal(TreeNode* root) { vector<int > res; inorder(res, root); return res; }};
class Solution {public: vector<int> inorderTraversal(TreeNode* root) { // write code here vector<int> res; stack<TreeNode *> s; while(root != NULL || !s.empty()){ while(root != NULL){ s.push(root); root = root->left; } TreeNode *node = s.top(); s.pop(); res.push_back(node->val); root = node->right; } return res; }};
class Solution {public: void postorder(vector<int> &res, TreeNode *root){ if(root == NULL) return; postorder(res, root->left); postorder(res, root->right); res.push_back(root->val); } vector<int> postorderTraversal(TreeNode* root) { // write code here vector<int> res; postorder(res, root); return res; }};
class Solution {public: vector<int> postorderTraversal(TreeNode* root) { vector<int> res; //辅助栈 stack<TreeNode*> s; TreeNode* pre = NULL; while(root != NULL || !s.empty()){ //每次先找到最左边的节点 while(root != NULL){ s.push(root); root = root->left; } //弹出栈顶 TreeNode* node = s.top(); s.pop(); //如果该元素的右边没有或是已经访问过 if(node->right == NULL || node->right == pre){ //访问中间的节点 res.push_back(node->val); //且记录为访问过了 pre = node; }else{ //该节点入栈 s.push(node); //先访问右边 root = node->right; } } return res; }};
class Solution {public: vector<vector<int> > levelOrder(TreeNode* root) { vector<vector<int> > res; if(root == NULL) //如果是空,则直接返回空vector return res; //队列存储,进行层次遍历 queue<TreeNode*> q; q.push(root); TreeNode* cur; while(!q.empty()){ //记录二叉树的某一行 vector<int> row; int n = q.size(); //因先进入的是根节点,故每层节点多少,队列大小就是多少 for(int i = 0; i < n; i++){ cur = q.front(); q.pop(); row.push_back(cur->val); //若是左右孩子存在,则存入左右孩子作为下一个层次 if(cur->left) q.push(cur->left); if(cur->right) q.push(cur->right); } //每一层加入输出 res.push_back(row); } return res; }};
class Solution {public: void traverse(TreeNode* root, vector<vector<int>>& res, int depth) { if(root){ //新的一层 if(res.size() < depth) res.push_back(vector<int>{}); //vector从0开始计数因此减1,在节点当前层的vector中插入节点 res[depth - 1].push_back(root->val); } else return; //递归左右时进入下一层 traverse(root->left, res, depth + 1); traverse(root->right, res, depth + 1); } vector<vector<int> > levelOrder(TreeNode* root) { vector<vector<int> > res; if(root == NULL) //如果是空,则直接返回空vector return res; traverse(root, res, 1); return res; }};
class Solution {public: vector<vector<int> > Print(TreeNode* pRoot) { vector<vector<int> > res; if (!pRoot) return res; queue<TreeNode*> q; // 定义队列 q.push(pRoot); // 根结点入队列 int level = 0; while (!q.empty()) { vector<int> arr; // 定义数组存储每一行结果 int size = q.size(); // 当前队列长度 for (int i = 0; i < size; i++) { TreeNode* tmp = q.front(); // 队头元素 q.pop(); if (!tmp) // 空元素跳过 continue; q.push(tmp->left); // 左孩子入队列 q.push(tmp->right); // 右孩子入队列 if (level % 2 == 0) { // 从左至右打印 arr.push_back(tmp->val); } else { // 从右至左打印 arr.insert(arr.begin(), tmp->val); } } level++; // 下一层,改变打印方向 if (!arr.empty()) res.push_back(arr); // 放入最终结果 } return res; }};
class Solution {public: vector<vector<int> > Print(TreeNode* pRoot) { vector<vector<int> > res; if (!pRoot) return res; stack<TreeNode*> stk1, stk2; // 定义两个栈 stk1.push(pRoot); // 根结点入栈 while (!stk1.empty() || !stk2.empty()) { // 两个栈全空时循环结束 vector <int> arr; while (!stk1.empty()) { TreeNode* p = stk1.top(); stk1.pop(); arr.push_back(p->val); // 访问栈顶 if (p->left) stk2.push(p->left); // 左孩子入栈 if (p->right) stk2.push(p->right); // 右孩子入栈 } if (arr.size()) res.push_back(arr); // 保存结果 arr.clear(); // 清空 while (!stk2.empty()) { TreeNode* p = stk2.top(); stk2.pop(); arr.push_back(p->val); // 访问栈顶 if (p->right) stk1.push(p->right); // 右孩子入栈 if (p->left) stk1.push(p->left); // 左孩子入栈 } if (arr.size()) res.push_back(arr); // 保存结果 } return res; }};
class Solution {public: int maxDepth(TreeNode* root) { //空节点没有深度 if(root == NULL) return 0; //返回子树深度+1 return max(maxDepth(root->left), maxDepth(root->right)) + 1; }};
class Solution {public: int maxDepth(TreeNode* root) { if(root == NULL) return 0 ; queue<TreeNode*> q; q.push(root); int res = 0; while(!q.empty()){ int n = q.size(); for(int i= 0; i< n; i++){ TreeNode *node = q.front(); q.pop(); if(node->left) q.push(node->left); if(node->right) q.push(node->right); } res++; } return res; }};
class Solution {public: bool hasPathSum(TreeNode* root, int sum) { // write code here if(root == NULL) return false; if(root->left == NULL && root->right == NULL && sum - root->val == 0) return true; return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val); }};
class Solution {public: bool hasPathSum(TreeNode* root, int sum) { // write code here if(root == NULL) return false; stack<pair<TreeNode *, int>> s; s.push({root, root->val}); while(!s.empty()){ auto temp = s.top(); s.pop(); if(temp.first->left == NULL && temp.first->right == NULL && temp.second == sum) return true; if(temp.first->left != NULL){ s.push({temp.first->left, temp.second + temp.first->left->val}); } if(temp.first->right != NULL){ s.push({temp.first->right, temp.second + temp.first->right->val}); } } return false; }};
class Solution {public: vector<TreeNode*> TreeList; void inorder(TreeNode* root){ if(!root) return; inorder(root->left); TreeList.push_back(root); inorder(root->right); } TreeNode* Convert(TreeNode* pRootOfTree) { if(!pRootOfTree) return pRootOfTree; inorder(pRootOfTree); for(int i=0; i<TreeList.size() - 1; i++){ TreeList[i]->right = TreeList[i+1]; TreeList[i+1]->left = TreeList[i]; } return TreeList[0]; }};
class Solution {public: //返回的第一个指针,即为最小值,先定为NULL TreeNode* head = NULL; //中序遍历当前值的上一位,初值为最小值,先定为NULL TreeNode* pre = NULL; TreeNode* Convert(TreeNode* pRootOfTree) { if(pRootOfTree == NULL) //中序递归,叶子为空则返回 return NULL; //首先递归到最左最小值 Convert(pRootOfTree->left); //找到最小值,初始化head与pre if(pre == NULL){ head = pRootOfTree; pre = pRootOfTree; } //当前节点与上一节点建立连接,将pre设置为当前值 else{ pre->right = pRootOfTree; pRootOfTree->left = pre; pre = pRootOfTree; } Convert(pRootOfTree->right); return head; }};
class Solution {public: bool recursion(TreeNode* root1, TreeNode* root2){ //可以两个都为空 if(root1 == NULL && root2 == NULL) return true; //只有一个为空或者节点值不同,必定不对称 if(root1 == NULL || root2 == NULL || root1->val != root2->val) return false; //每层对应的节点进入递归 return recursion(root1->left, root2->right) && recursion(root1->right, root2->left); } bool isSymmetrical(TreeNode* pRoot) { return recursion(pRoot, pRoot); }};
class Solution {public: bool isSymmetrical(TreeNode* pRoot) { //空树为对称的 if(pRoot == NULL) return true; //辅助队列用于从两边层次遍历 queue<TreeNode*> q1; queue<TreeNode*> q2; q1.push(pRoot->left); q2.push(pRoot->right); while(!q1.empty() && !q2.empty()){ //分别从左边和右边弹出节点 TreeNode* left = q1.front(); q1.pop(); TreeNode* right = q2.front(); q2.pop(); //都为空暂时对称 if(left == NULL && right == NULL) continue; //某一个为空或者数字不相等则不对称 if(left == NULL || right == NULL || left->val != right->val) return false; //从左往右加入队列 q1.push(left->left); q1.push(left->right); //从右往左加入队列 q2.push(right->right); q2.push(right->left); } //都检验完都是对称的 return true; }};
class Solution {public: TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { // write code here if(t1 == NULL) return t2; if(t2 == NULL) return t1; TreeNode *head = new TreeNode(t1->val+t2->val); head->left = mergeTrees(t1->left, t2->left); head->right = mergeTrees(t1->right, t2->right); return head; }};
class Solution {public: TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { //若只有一个节点返回另一个,两个都为NULL自然返回NULL if (t1 == NULL) return t2; if (t2 == NULL) return t1; //合并根节点 TreeNode* head = new TreeNode(t1->val + t2->val); //连接后的树的层次遍历节点 queue<TreeNode*> q; //分别存两棵树的层次遍历节点 queue<TreeNode*> q1; queue<TreeNode*> q2; q.push(head); q1.push(t1); q2.push(t2); while (!q1.empty() && !q2.empty()) { TreeNode *node = q.front(), *node1 = q1.front(), *node2 = q2.front(); q.pop(); q1.pop(); q2.pop(); TreeNode *left1 = node1->left, *left2 = node2->left, *right1 = node1->right, *right2 = node2->right; //两个左节点都存在 if (left1 || left2) { if (left1 && left2) { TreeNode* left = new TreeNode(left1->val + left2->val); node->left = left; //新节点入队列 q.push(left); q1.push(left1); q2.push(left2); //只连接一个节点 } else if (left1) node->left = left1; else if (left2) node->left = left2; } if (right1 || right2) { //两个右节点都存在 if (right1 && right2) { TreeNode* right = new TreeNode(right1->val + right2->val); node->right = right; //新节点入队列 q.push(right); q1.push(right1); q2.push(right2); //只连接一个节点 } else if (right1) node->right = right1; else node->right = right2; } } return head; }};
class Solution {public: TreeNode* Mirror(TreeNode* pRoot) { // write code here if(pRoot == NULL) return pRoot; swap(pRoot->left, pRoot->right); Mirror(pRoot->left); Mirror(pRoot->right); return pRoot; }};
class Solution {public: TreeNode* Mirror(TreeNode* pRoot) { // write code here if(pRoot == NULL) return pRoot; stack<TreeNode *> s; s.push(pRoot); while(!s.empty()){ TreeNode *node = s.top(); s.pop(); if(node->left != NULL) s.push(node->left); if(node->right != NULL) s.push(node->right); TreeNode *temp = node->right; node->right = node->left; node->left = temp; } return pRoot; }};
递归的方式:
class Solution {public: long pre = INT_MIN; bool isValidBST(TreeNode* root) { // write code here if(root == NULL) return true; if(!isValidBST(root->left)) return false; if(root->val <= pre) return false; pre = root->val; if(!isValidBST(root->right)) return false; return true; }};
public: long pre = INT_MIN; bool isValidBST(TreeNode* root) { // write code here stack<TreeNode *> s; TreeNode *head = root; vector<int> sort; while(head != NULL || !s.empty()){ while(head != NULL){ s.push(head); head = head->left; } head = s.top(); s.pop(); sort.push_back(head->val); head = head->right; } for(int i=1; i<sort.size(); i++){ if(sort[i-1] > sort[i]) return false; } return true; }};
首先判断空树是完全二叉树,采用队列方式,每次入队一个层次,如果该层没有空节点则继续遍历,如果有空节点就设置flag为TRUE,即标志着有空节点,接下去不应该有下一个
bool isCompleteTree(TreeNode* root) { if(root == NULL) return true; queue<TreeNode *> q; q.push(root); bool flag = false; while(!q.empty()){ int sz = q.size(); for(int i=0; i<sz; i++){ TreeNode *cur = q.front(); q.pop(); if(cur == NULL) flag = true; else{ if(flag) return false; q.push(cur->left); q.push(cur->right); } } } return true; }
自底向上的思路,先求出左树和右树的高度,递归得到左树右树是否为平衡二叉树,最后判断左树和右树的绝对值是否相差1
class Solution {public: int depth(TreeNode *root){ if(!root) return 0; int ldep = depth(root->left); if(ldep == -1) return -1; int rdep = depth(root->right); if(rdep == -1) return -1; int sub = abs(ldep - rdep); if(sub > 1) return -1; return max(ldep, rdep) + 1; } bool IsBalanced_Solution(TreeNode* pRoot) { return depth(pRoot) != -1; }};
查找两节点的最近的公共祖先,在这里我是采用左神的思路,如果遇到了只遇到其中一个结点,那就直接返回该结点,另一个结点一定是它的子节点;如果两节点不在同一边的树,那最终就会返回头结点;最后一种就是返回两节点往上返回时遇到的第一个结点,因为这个结点的左右不为空,所以会是公共祖先。
这种方法可以适用于普通二叉树
TreeNode *dfs(TreeNode *head, int o1, int o2){ if(!head || head->val == o1 || head->val == o2) return head; TreeNode *left = dfs(head->left,o1,o2); TreeNode *right = dfs(head->right,o1,o2); if(left != NULL && right != NULL) return head; return left != NULL ? left :right; } int lowestCommonAncestor(TreeNode* root, int p, int q) { // write code here return dfs(root, p, q)->val; }
比较法,因为这是二叉搜索树,可以先判断pq与节点大小关系
class Solution {public: int lowestCommonAncestor(TreeNode* root, int p, int q) { //空树找不到公共祖先 if(root == NULL) return -1; //pq在该节点两边说明这就是最近公共祖先 if((p >= root->val && q <= root->val) || (p <= root->val && q >= root->val)) return root->val; //pq都在该节点的左边 else if(p <= root->val && q <= root->val) //进入左子树 return lowestCommonAncestor(root->left, p, q); //pq都在该节点的右边 else //进入右子树 return lowestCommonAncestor(root->right, p, q); }};
通过前序遍历确定头结点,然后找到头结点在中序遍历所在位置,分为左子树和右子树,然后递归该过程
class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) { int n = pre.size(); int m = vin.size(); if (n == 0 || m == 0) return NULL; TreeNode* root = new TreeNode(pre[0]); for (int i = 0; i < vin.size(); i++) { if (pre[0] == vin[i]) { vector<int> leftpre(pre.begin() + 1, pre.begin() + i + 1); vector<int> leftvin(vin.begin() , vin.begin() + i ); root->left = reConstructBinaryTree(leftpre, leftvin); vector<int> rigthpre(pre.begin() +i+ 1, pre.end()); vector<int> rightvin(vin.begin() +i+ 1, vin.end()); root->right = reConstructBinaryTree(rigthpre, rightvin); break; } } return root; }};
class Solution {public: //建树函数 //四个int参数分别是前序最左节点下标,前序最右节点下标 //中序最左节点下标,中序最右节点坐标 TreeNode* buildTree(vector<int>& xianxu, int l1, int r1, vector<int>& zhongxu, int l2, int r2) { if(l1 > r1 || l2 > r2) return NULL; //构建节点 TreeNode* root = new TreeNode(xianxu[l1]); //用来保存根节点在中序遍历列表的下标 int rootIndex = 0; //寻找根节点 for(int i = l2; i <= r2; i++){ if(zhongxu[i] == xianxu[l1]){ rootIndex = i; break; } } //左子树大小 int leftsize = rootIndex - l2; //右子树大小 int rightsize = r2 - rootIndex; //递归构建左子树和右子树 root->left = buildTree(xianxu, l1 + 1, l1 + leftsize, zhongxu, l2 , l2 + leftsize - 1); root->right = buildTree(xianxu, r1 - rightsize + 1, r1, zhongxu, rootIndex + 1, r2); return root; } //深度优先搜索函数 vector<int> rightSideView(TreeNode* root) { //右边最深处的值 unordered_map<int, int> mp; //记录最大深度 int max_depth = -1; //维护深度访问节点 stack<TreeNode*> nodes; //维护dfs时的深度 stack<int> depths; nodes.push(root); depths.push(0); while (!nodes.empty()){ TreeNode* node = nodes.top(); nodes.pop(); int depth = depths.top(); depths.pop(); if (node != NULL) { //维护二叉树的最大深度 max_depth = max(max_depth, depth); //如果不存在对应深度的节点我们才插入 if (mp.find(depth) == mp.end()) mp[depth] = node->val; nodes.push(node->left); nodes.push(node->right); depths.push(depth + 1); depths.push(depth + 1); } } vector<int> res; for (int i = 0; i <= max_depth; i++) res.push_back(mp[i]); return res; } vector<int> solve(vector<int>& xianxu, vector<int>& zhongxu) { vector<int> res; //空节点 if(xianxu.size() == 0) return res; //建树 TreeNode* root = buildTree(xianxu, 0, xianxu.size() - 1, zhongxu, 0, zhongxu.size() - 1); //找每一层最右边的节点 return rightSideView(root); }};
使用队列和栈的方法,把当前层次的节点都放入,然后当该层的节点都遍历完,取最后一个结点就是最右的节点
class Solution {public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 求二叉树的右视图 * @param xianxu int整型vector 先序遍历 * @param zhongxu int整型vector 中序遍历 * @return int整型vector */ unordered_map<int, int> index; TreeNode *buildTree(vector<int>& xianxu, int l1, int r1, vector<int>& zhongxu, int l2, int r2){ if(l1>r1 || l2>r2)return NULL; TreeNode *root = new TreeNode(xianxu[l1]); int rootIndex = 0; for(int i=l2; i<=r2; i++){ if(zhongxu[i] == xianxu[l1]){ rootIndex = i; break; } } int leftsize = rootIndex - l2; int rightsize = r2 - rootIndex; root->left = buildTree(xianxu,l1+1, l1+leftsize, zhongxu, l2, l2+leftsize-1); root->right = buildTree(xianxu, r1 - rightsize + 1, r1, zhongxu, rootIndex + 1, r2); return root; } vector<int> rightSideView(TreeNode *root){ vector<int> res; queue<TreeNode*> q; q.push(root); while(!q.empty()){ int size = q.size(); while(size--){ TreeNode *temp = q.front(); q.pop(); if(temp->left) q.push(temp->left); if(temp->right) q.push(temp->right); if(size == 0) res.push_back(temp->val); } } return res; } vector<int> solve(vector<int>& xianxu, vector<int>& zhongxu) { // write code here vector<int> res; if(xianxu.size() == 0)return res; for(int i=0; i<xianxu.size(); i++)index[zhongxu[i]] =i; TreeNode* root= buildTree(xianxu, 0, xianxu.size()-1, zhongxu, 0, zhongxu .size()-1); return rightSideView(root); }};