145. 二叉树的后序遍历
难度中等550
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
145-1.后序遍历非递归
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ans;
if(root == nullptr) return ans;
stack<TreeNode* > stk;
TreeNode* prev = nullptr;
while(!stk.empty() || root != nullptr){
while(root != nullptr){
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
//root->right = prev的情况是当前root是某个父结点,且左右子结点都已经遍历完毕
//1.遍历到子节点 || 2.子树已经遍历完了,根节点进入
if(root->right == nullptr || root->right == prev){
ans.push_back(root->val);
prev = root;
root = nullptr;
}else{//有右节点就先遍历右节点
stk.push(root);
root = root->right;
}
}
return ans;
}
};
145-2.中序遍历非递归
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans;
if(root == nullptr){
return ans;
}
stack<TreeNode* > stk;
while(!stk.empty() || root != nullptr){
while(root){
stk.push(root);
root = root->left;
}
ans.push_back(stk.top()->val);
root = stk.top();
stk.pop();
root = root->right;
}
return ans;
}
};
145-3.前序遍历非递归
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
if(root == nullptr) return {};
stack<TreeNode* > stk;
vector<int> ans;
while(!stk.empty() || root != nullptr){
while(root != nullptr){
stk.push(root);
ans.push_back(stk.top()->val);
root = root->left;
}
root = stk.top();
stk.pop();
root = root->right;
}
return ans;
}
};
230. 二叉搜索树中第K小的元素
这里写的是非递归的迭代解法
难度中等368
给定一个二叉搜索树的根节点 root
,和一个整数 k
,请你设计一个算法查找其中第 k
个最小元素(从 1 开始计数)。
示例 1:
输入:root = [3,1,4,null,2], k = 1
输出:1
示例 2:
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
提示:
- 树中的节点数为
n
。 1 <= k <= n <= 104
0 <= Node.val <= 104
进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第k
小的值,你将如何优化算法?class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
vector<int> ans;
stack<TreeNode* > stk;
TreeNode* cur = root;
while(!stk.empty() || cur){
//左边先尽量入
while(cur){
stk.push(cur);
cur = cur->left;
}
cur = stk.top();
stk.pop();
ans.push_back(cur->val);
cur = cur->right;
}
return ans[k - 1];
}
};
235. 二叉搜索树的最近公共祖先
利用BST的特性,只要找满足根结点实在两个目标结点的中间即可
难度简单555
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2
和节点 8
的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2
和节点 4
的最近公共祖先是 2
, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉搜索树中。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root){
if(root->val > p->val && root->val > q->val){
root = root->left;
}else if(root->val < p->val && root->val < q->val){
root = root->right;
}else{
break;
}
}
return root;
}
};
236. 二叉树的最近公共祖先
少了搜索树的特点,但其实还是可以用类似的想法,做好递归。从根部开始,本身的函数功能就是根据两个目标结点,找到祖先点然后返回,递归也就要抓住这点。
难度中等1017
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5
和节点 1
的最近公共祖先是节点 3 。
示例 2:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5
和节点 4
的最近公共祖先是节点 5 。
因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
提示:
- 树中节点数目在范围
[2, 105]
内。 -109 <= Node.val <= 109
- 所有
Node.val
互不相同
。 p != q
p
和q
均存在于给定的二叉树中。class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
//两种终止条件
if(root == nullptr) return nullptr;
//如果遍历到p 和 q那么也终止,说明找到p或者q了
//这是利用了公共祖先本身允许 祖先是自己
if(root == p || root == q){
return root;
}
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
//对于左右子树分别判断
//1.如果左右子树中都不包含p或q 那么就返回空
if(left == nullptr && right == nullptr) return nullptr;
//2. 3.如果左右子树任意一个为空 那么返回另一边的子数寻找
if(left == nullptr) return right;
if(right == nullptr) return left;
//4.都找到了,那么满足条件,直接返回root 即最近公共祖先
return root;
}
};
剑指 Offer 26. 树的子结构
难度中等248
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:3<br /> / \<br /> 4 5<br /> / \<br /> 1 2
给定的树 B:4 <br /> /<br /> 1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
限制:0 <= 节点个数 <= 10000
class Solution {
public:
//进行当前结构下的匹配
bool helper(TreeNode* A, TreeNode* B){
//因为B是A的子结构,所以A的结构应该要>=B,所以不应当先出现A为空的情况
if(B == nullptr) return true;
if(A == nullptr) return false;
//注意这里是值相等,不能用节点等
if(A->val == B->val) return helper(A->left, B->left) && helper(A->right, B->right);
return false;
}
//找第一个匹配点
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(A == nullptr || B == nullptr){
return false;
}
//这必须要把判定子树的过程写到分支中
//不然如果有重复的节点值时,会直接返回false,可能会错过子结构
if(A->val == B->val && helper(A->left, B->left) && helper(A->right, B->right)){
return true;
}
return isSubStructure(A->left, B) || isSubStructure(A->right, B);
}
};
剑指 Offer II 049. 从根节点到叶节点的路径数字之和
先序遍历