目录
1. T669:修剪二叉树
T669:给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
提示:
-
树中节点数在范围 [1, 104] 内
-
0 <= Node.val <= 104
-
树中每个节点的值都是 唯一 的
-
题目数据保证输入是一棵有效的二叉搜索树
-
0 <= low <= high <= 104
S:
总结一句话:遇到不在指定区间内的节点A,就去找符合的节点,直到找到之后,就让符合的节点取代节点A成为子节点
1.1 法1、递归法
C++:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (!root) return nullptr;
if (root->val < low) {
return trimBST(root->right, low, high);// 寻找符合区间[low, high]的节点
} else if (root->val > high) {
return trimBST(root->left, low, high);
}
root->left = trimBST(root->left, low, high);// root->left接入符合条件的左孩子
root->right = trimBST(root->right, low, high);
return root;
}
Java:
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) return null;
if (root.val < low) {
return trimBST(root.right, low, high);
} else if (root.val > high) {
return trimBST(root.left, low, high);
}
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
1.2 法2、迭代法
迭代法里面还有几点没完全想清楚。。。(🚩处)
C++:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (!root) return nullptr;
//处理头节点,让root移动到[L, R] 范围内,注意是左闭右闭
while (root && (root->val < low || root->val > high)) {
if (root->val < low) {
root = root->right;
} else {
root = root->left;
}
}
TreeNode* cur = root;
// 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
while (cur) {//🚩如果没有这一行,error:[3] 2
while (cur->left && cur->left->val < low) {
cur->left = cur->left->right;
}
cur = cur->left;//🚩这一行的作用没看懂,没有就超时
}
cur = root;//一定要重新赋值!
while (cur) {
while (cur->right && cur->right->val > high) {
cur->right = cur->right->left;
}
cur = cur->right;//这一行的作用没看懂
}
return root;
}
Java:
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) return null;
// while (root.val < low || root.val > high) {//🚩没标明root非空->error:[3] 2
// while (root != null && root.val < low || root.val > high) {//没内层括号:error
while (root != null && (root.val < low || root.val > high)) {
if (root.val < low) {
root = root.right;
} else {
root = root.left;
}
}
TreeNode cur = root;
while (cur != null) {//跟首个注释error的那行一样,必须有
while (cur.left != null && cur.left.val < low) {
cur.left = cur.left.right;
}
cur = cur.left;
}
cur = root;
while (cur != null) {
while (cur.right != null && cur.right.val > high) {
cur.right = cur.right.left;
}
cur = cur.right;
}
return root;
}
2. T108:将有序数组转换为BST
T108:给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
提示:
-
1 <= nums.length <= 104
-
-104 <= nums[i] <= 104
-
nums 按 严格递增 顺序排列
S:只要每次都取中值做根节点,构造出的二叉树天然就会高度平衡~
2.1 法1、递归
C++:
//【左闭右闭】
TreeNode* sortedArrayToBST(vector<int>& nums) {
// if (nums.size() == 0) return nullptr;
return sortedArrayToBST(nums, 0, nums.size() - 1);
}
private:
TreeNode* sortedArrayToBST(vector<int>& nums, int left, int right) {
if (left > right) return nullptr;//1、注意要不要=
int mid = (left + right) / 2;
// int mid = left + ((right - left) / 2);
TreeNode* root = new TreeNode(nums[mid]);
root->left = sortedArrayToBST(nums, left, mid - 1);
root->right = sortedArrayToBST(nums, mid + 1, right);
return root;
}
//【左闭右开】
TreeNode* sortedArrayToBST(vector<int>& nums) {
// if (nums.size() == 0) return nullptr;
return sortedArrayToBST(nums, 0, nums.size());
}
private:
TreeNode* sortedArrayToBST(vector<int>& nums, int left, int right) {
if (left >= right) return nullptr;//1、注意
// if (right - left == 1) return new TreeNode(nums[0]);//2、犯傻
if (right - left == 1) return new TreeNode(nums[left]);//其实没有这行也可以
// int mid = left + ((right - left) >>> 1);//3、不知为何,用无符号右移就编译error,二分法都可以
int mid = left + ((right - left) >> 1);
TreeNode* root = new TreeNode(nums[mid]);
root->left = sortedArrayToBST(nums, left, mid);
root->right = sortedArrayToBST(nums, mid + 1, right);
return root;
}
Java:
//【左闭右闭】
public TreeNode sortedArrayToBST(int[] nums) {
return sortedArrayToBST(nums, 0, nums.length - 1);
}
private TreeNode sortedArrayToBST(int[] nums, int left, int right) {
if (left > right) return null;
int mid = left + ((right - left) >> 1);
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST(nums, left, mid - 1);
root.right = sortedArrayToBST(nums, mid + 1, right);
return root;
}
//【左闭右开】
public TreeNode sortedArrayToBST(int[] nums) {
return sortedArrayToBST(nums, 0, nums.length);
}
private TreeNode sortedArrayToBST(int[] nums, int left, int right) {
if (left >= right) return null;
int mid = left + ((right - left) >> 1);
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST(nums, left, mid);
root.right = sortedArrayToBST(nums, mid + 1, right);
return root;
}
2.2 法2、迭代
C++:
TreeNode* sortedArrayToBST(vector<int>& nums) {
if (nums.size() == 0) return nullptr;
TreeNode* root = new TreeNode(nums[nums.size() / 2]);
queue<TreeNode*> nodeQue;
nodeQue.push(root);
queue<int> leftQue;
leftQue.push(0);
queue<int> rightQue;
rightQue.push(nums.size() - 1);
while (!nodeQue.empty()) {
TreeNode* curNode = nodeQue.front();
nodeQue.pop();
int left = leftQue.front();
leftQue.pop();
int right = rightQue.front();
rightQue.pop();
int mid = (left + right) / 2;
curNode->val = nums[mid];// 【易漏】将mid对应的元素给中间节点
if (left <= mid - 1) {// 处理左区间
curNode->left = new TreeNode(0);
nodeQue.push(curNode->left);
leftQue.push(left);
rightQue.push(mid - 1);
}
if (right >= mid + 1) {// 处理右区间
curNode->right = new TreeNode(0);
nodeQue.push(curNode->right);
leftQue.push(mid + 1);
rightQue.push(right);
}
}
return root;
}
Java:
public TreeNode sortedArrayToBST(int[] nums) {
if (nums.length == 0) return null;
Deque<TreeNode> nodeQue = new LinkedList<>();
TreeNode root = new TreeNode(0);
nodeQue.push(root);
Deque<Integer> leftQue = new LinkedList<>();
leftQue.offerLast(0);
Deque<Integer> rightQue = new LinkedList<>();
rightQue.add(nums.length);
while (!nodeQue.isEmpty()) {
TreeNode curNode = nodeQue.pop();
Integer left = leftQue.removeFirst();
Integer right = rightQue.pollFirst();
int mid = (left + right) / 2;
curNode.val = nums[mid];// 【易漏】将mid对应的元素给中间节点
// if (left <= mid) {//导致索引越界
if (left < mid) {
curNode.left = new TreeNode(nums[mid]);
nodeQue.add(curNode.left);
leftQue.add(left);
rightQue.add(mid);
}
// if (right >= mid + 1) {
if (right > mid + 1) {
curNode.right = new TreeNode(nums[mid]);
nodeQue.add(curNode.right);
leftQue.add(mid + 1);
rightQue.add(right);
}
}
return root;
}
3. T538:把BST转换为累加树
T538:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
-
节点的左子树仅包含键 小于 节点键的节点。
-
节点的右子树仅包含键 大于 节点键的节点。
-
左右子树也必须是二叉搜索树。
提示:
-
树中的节点数介于 0 和 104 之间。
-
每个节点的值介于 -104 和 104 之间。
-
树中的所有值 互不相同 。
-
给定的树为二叉搜索树。
S:虽然自己想着从左向右中序遍历,但实际上反中序遍历解起来更加便捷(不用每次都遍历所有大于自己的节点)
3.1 递归
C++:
TreeNode* convertBST(TreeNode* root) {
traversal(root);
return root;
}
private:
int preSum;
void traversal(TreeNode* cur) {
if (!cur) return;
traversal(cur->right);
cur->val += preSum;
preSum = cur->val;
traversal(cur->left);
}
Java:
int preSum = 0;
public TreeNode convertBST(TreeNode root) {
traversal(root);
return root;
}
private void traversal(TreeNode cur) {
if (cur == null) return;
traversal(cur.right);
cur.val += preSum;
preSum = cur.val;
traversal(cur.left);
}
3.2 迭代
C++:
//【普通迭代】
TreeNode* convertBST(TreeNode* root) {
int preSum = 0;
TreeNode* cur = root;
stack<TreeNode*> st;
while (cur || !st.empty()) {
if (cur) {
st.push(cur);
cur = cur->right;
} else {
// st.pop();
cur = st.top();
st.pop();
cur->val += preSum;
preSum = cur->val;
cur = cur->left;
}
}
return root;
}
//【统一迭代】
TreeNode* convertBST(TreeNode* root) {
if (!root) return nullptr;
stack<TreeNode*> st;
st.push(root);
int preSum = 0;
while (!st.empty()) {
TreeNode* cur = st.top();
if (cur) {
st.pop();
if (cur->left) st.push(cur->left);
st.push(cur);
st.push(nullptr);
if (cur->right) st.push(cur->right);
} else {
st.pop();
cur = st.top();
st.pop();
cur->val += preSum;
preSum = cur->val;
}
}
return root;
}
Java:
//【普通迭代】
public TreeNode convertBST(TreeNode root) {
int preSum = 0;
Deque<TreeNode> stack = new LinkedList<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.right;
} else {
cur = stack.pop();
cur.val += preSum;
preSum = cur.val;
cur = cur.left;
}
}
return root;
}
//【统一迭代】
public TreeNode convertBST(TreeNode root) {
if (root == null) return null;
int preSum = 0;
Deque<TreeNode> stack = new LinkedList<>();
stack.offerFirst(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.pop();
if (cur != null) {
if (cur.left != null) stack.push(cur.left);
stack.addFirst(cur);
stack.addFirst(null);
if (cur.right != null) stack.push(cur.right);
} else {
cur = stack.removeFirst();
cur.val += preSum;
preSum = cur.val;
}
}
return root;
}