20天 hot 100 速通计划-day09
二叉树
102. 二叉树的层序遍历
给你二叉树的根节点 root
,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:
输入:root = [1]
输出:[[1]]
示例 3:
输入:root = []
输出:[]
提示:
- 树中节点数目在范围
[0, 2000]
内 -1000 <= Node.val <= 1000
纯技巧原子操作,本质上就是栈的应用,属于二叉树中少见的非递归处理方法
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
//用于记录多层遍历结果
vector<vector<int>> res;
//剪枝:空树直接不处理
if(root==nullptr) return res;
//处理工具:栈
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
//用于记录单层遍历结果
vector<int> level;
//会变,所以单独设置为 size,实时更新
int size = q.size();
for(int i = 0; i < size; i++){
//注意:front() 只取值,不弹出,需要之后额外调用 pop() 弹出
TreeNode* cur = q.front();
//注意:front() 只弹出,不取值,需要之前额外调用 front() 取值
q.pop();
//单层结果记录
level.push_back(cur->val);
//下一层入栈
if(cur->left!=nullptr){
q.push(cur->left);
}
if(cur->right!=nullptr){
q.push(cur->right);
}
}
//多层结果记录
res.push_back(level);
}
return res;
}
}
108. 将有序数组转换为二叉搜索树
给你一个整数数组 nums
,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
示例 2:
输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
按 严格递增 顺序排列
原子操作
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return buildBST(nums, 0, nums.size() - 1);
}
//参返分析:输入有序数组,左右子树的值,输出二叉搜索树
//终止条件:左 > 右
//单层逻辑:二分法,中间作为根节点,一半作为左子树,一半作为右子树
TreeNode* buildBST(vector<int>& nums, int left, int right) {
if (left > right) {
return nullptr;
}
//减法求中点,防溢出
int mid = left + (right - left) / 2;
TreeNode* root = new TreeNode(nums[mid]);
root->left = buildBST(nums, left, mid - 1);
root->right = buildBST(nums, mid + 1, right);
return root;
}
};
98. 验证二叉搜索树
给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3]
输出:true
示例 2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
提示:
- 树中节点数目范围在
[1, 104]
内 -231 <= Node.val <= 231 - 1
原子操作
class Solution {
public:
long pre = LONG_MIN;
//关键:中序遍历得升序数组,魔改中序遍历即可判断
//参返分析:输入根节点,输出判断结果
//终止条件:当前节点为空,直接返回 true
//单层逻辑:魔改中序遍历,判断左子树,处理根节点(更新 pre),判断右子树
bool func(TreeNode* root){
if(!root) return true;
// 访问左子树
if(!isValidBST(root->left)) return false;
// 访问当前节点
//如果当前节点小于等于中序遍历的前一个节点,说明不满足BST,返回 false;否则继续遍历。
if(root->val <= pre) return false;
pre = root->val;
// 访问右子树
return isValidBST(root->right);
}
bool isValidBST(TreeNode* root) {
return func(root);
}
};
230. 二叉搜索树中第K小的元素
给定一个二叉搜索树的根节点 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
class Solution {
public:
//关键:中序遍历得递增数组
//先中序遍历,再取第k个元素(下标 k-1)
void inorderTraversal(TreeNode* root, vector<int>& nodes) {
if (root == nullptr) {
return;
}
inorderTraversal(root->left, nodes);
nodes.push_back(root->val);
inorderTraversal(root->right, nodes);
}
int kthSmallest(TreeNode* root, int k) {
vector<int> nodes;
inorderTraversal(root, nodes);
return nodes[k-1];
}
}
199. 二叉树的右视图
给定一个二叉树的 根节点 root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例 1:
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
示例 2:
输入: [1,null,3]
输出: [1,3]
示例 3:
输入: []
输出: []
提示:
- 二叉树的节点个数的范围是
[0,100]
-100 <= Node.val <= 100
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if (root == nullptr) {
return result;
}
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int size = q.size();
//与纯粹层序遍历不同,此处没有引入记录单层数值的 level 数组
//vector<int> level;
for (int i = 0; i < size; i++) {
TreeNode* node = q.front();
q.pop();
//与纯粹层序遍历不同,此处只在 i 为最右侧节点时记录值
//level.push_back(node->val);
if (i == size - 1) {
result.push_back(node->val);
}
if (node->left != nullptr) {
q.push(node->left);
}
if (node->right != nullptr) {
q.push(node->right);
}
}
//与纯粹层序遍历不同,此处没有引入记录多层数值的 res 数组,也不按层记录
//res.push_back(level);
}
return result;
}
};