持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
94. 二叉树的中序遍历
思路
思路1
(递归)
按照 左子树 => 根节点 => 右子树的顺序进行遍历二叉树。
c++代码1
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> res;
vector<int> inorderTraversal(TreeNode* root) {
dfs(root);
return res;
}
void dfs(TreeNode* root){
if(!root) return ;
dfs(root->left);
res.push_back(root->val);
dfs(root->right);
}
};
思路2
(迭代)
假设当前树的根节点为root,如果root != null,将整颗树的左链压入栈中。此时的栈顶元素就是我们想要的中序遍历结果,将其加入res中。如果有右子树,按照相同的步骤处理右子树。
c++代码2
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
while(root || stk.size()){
while(root){ //将左子链压入栈中
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
res.push_back(root->val); // 当前栈顶元素就是中序遍历的结果
root = root->right; //处理右子树
}
return res;
}
};
96. 不同的二叉搜索树
思路
(动态规划) O(n^2)
状态表示: f[n]表示n个节点的二叉搜索树一共有多少种?
状态计算:
当给定的二叉树节点固定时,对应的二叉搜索树的情况数量也一定固定。对于节点数为i的二叉搜索树,我们去枚举二叉树的根节点的位置j,那么左子树区间为[1, j - 1],节点数为j - 1,右子树区间为[j + 1, i],节点数为[i - j]。将左子树长度和右子树的长度相乘就是节点数为i,根节点位置为j二叉树的种类,即f[i] = f[j - 1] * f[i - j]。
而对于长度为n的二叉树,根据根节点位置的划分,左子树可以有 0,1,…n−1 个节点,对应的右子树有 n−1,n−2,…,0 个节点,f[n] 是所有这些情况的加和,所以f[n] = \sum_{k=0}^{n-1}f[k]*f[n-1-k] 。
初始化:
f[0]= 1,节点数为0的二叉树只有一种,为空树。
时间复杂度分析: 状态总共有 n 个,状态转移的复杂度是 O(n),所以总时间复杂度是 O(n^2)。
c++代码
class Solution {
public:
int numTrees(int n) {
vector<int>f(n + 1);
f[0] = 1;
for(int i = 1; i <= n; i++) // 枚举二叉树的长度
for(int j = 1; j <= i; j++) // 枚举根节点所在的位置
f[i] += f[j - 1] * f[i - j]; //左子树长度 * 右子树长度 (映射)
return f[n];
}
};
98. 验证二叉搜索树
思路
(深度优先遍历) O(n)
二叉搜索树是一种节点值之间具有一定数量级次序的二叉树,对于树中每个节点:
- 若其左子树存在,则其左子树中每个节点的值都小于该节点值;
- 若其右子树存在,则其右子树中每个节点的值都大于该节点值。
我们知道二叉搜索树**「中序遍历」**得到的值构成的序列一定是升序的的。因此我们可以对二叉树进行中序遍历,判断当前节点是否大于中序遍历的前一个节点,如果大于,说明说明这个序列是升序的,整棵树是二叉搜索树,否则不是。
二叉树的中序遍历顺序为: 左根右
图示:
过程:
- 1、我们定义一个节点变量
pre用来记录中序遍历的前一个节点。 - 2、中序遍历二叉树,在遍历过程中判断当前节点是否大于中序遍历的前一个节点。如果大于不做任何处理,如果小于等于说明不满足二叉搜索树的性质,返回
false。
细节:
- 1、
pre节点的初始值要设置为null。 - 2、具体实现过程看代码。
时间复杂度分析: 树中每个节点仅被遍历一遍,所以时间复杂度是 O(n)。
c++代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* pre = nullptr;
bool isValidBST(TreeNode* root) {
if(!root ) return true; //递归边界
//判断当前节点的左子树是否满足二叉搜索树,如果不满足,直接返回false,无序递归右子树
if(!isValidBST(root->left) ) return false;
//如果前一个节点不为空并且当前节点<=前一个节点,直接返回false
if( pre && root->val <= pre->val) return false;
//否则,将当前节点设置为pre
pre = root;
return isValidBST(root->right); //递归判断右子树
}
};