刷题笔记
- 二叉树算法专栏
- leetcode 814. 二叉树剪枝
- leetcode上二叉树的建树测试代码
- leetcode 94 二叉树的中序遍历
- leetcode 144 二叉树的前序遍历
- leetcode 145 二叉树的后序遍历
- leetcode 102 二叉树的层序遍历
- leetcode 107 二叉树的层序遍历II
- leetcode 119 二叉树的右视图
- leetcode 637 二叉树的层平均值
- leetcode 429 N叉树的层序遍历
- leetcode 515 在每个树行中找到最大值
- leetcode 116 填充每个节点的下一个右侧节点指针
- leetcode 117 填充每个节点的下一个右侧节点指针II
- leetcode 104 二叉树的最大深度
- leetcode 559 N叉树的最大深度
- leetcode 111 二叉树的最小深度
- leetcode 226 翻转二叉树
- leetcode 101 对称二叉树
- leetcode 100 相同的树
- leetcode 572 另一颗树的子树
- leetcode 222 完全二叉树的节点个数
- leetcode 110 平衡二叉树
- leetcode 563 二叉树的坡度
- leetcode 543 二叉树的直径
- leetcode 538 把二叉搜索树转换为累加树
- leetcode 404 左叶子之和
- leetcode 513 找树左下角的值
- leetcode 257 二叉树的所有路径
- leetcode 112 路径总和
- leetcode 113 路径总和II
- leetcode 437 路径总和III
- leetcode 124 二叉树中的最大路径和
- leetcode 617 合并二叉树
- leetcode 700 二叉搜索树中的搜索
- leetcode 98 验证二叉搜索树
- leetcode 958 二叉树的完全性检验
- leetcode 530 二叉搜索树的最小绝对差
- leetcode 501 二叉搜索树中的众数
- leetcode 236 二叉树的最近公共祖先
- leetcode 235 二叉搜索树的最近公共祖先
- leetcode 701 二叉搜索树中的插入操作
- leetcode 450 删除二叉搜索树中的节点
- leetcode 669 修剪二叉搜索树
- leetcode 108 将有序数组转换为二叉搜索树
- leetcode 95 不同的二叉搜索树 II
- leetcode 106 从中序与后序遍历序列构造二叉树
- leetcode 106 从前序与中序遍历序列构造二叉树
- leetcode 654 最大二叉树
- 题目一:建立顺序存储结构存储的二叉树
- 题目二:判断顺序存储结构存储的二叉树是否为二叉搜索树
- 题目三:二叉树中查找值为x的结点,输出值为x的结点的所有祖先
- 题目四:二叉树中判断双分支结点的个数
- 题目五:假设二叉树采用二叉链表存储设计,设计一个算法,求先序遍历序列中第k个结点的值。
- 题目六:已知二叉树以二叉链表存储,编写算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间。
二叉树算法专栏
leetcode 814. 二叉树剪枝
class Solution {
public:
TreeNode* pruneTree(TreeNode* root) {
if (!root) return NULL;
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
// if (root->left == NULL && root->right == NULL && root->val == 0) {
// return NULL;
// }
if (root->left != NULL || root->right != NULL) return root;
return root->val == 0 ? NULL : root;
}
};
核心思想:
使用 后序遍历(左 -> 右 -> 根)递归地处理每个节点。
对于每个节点:
如果它的左子树不包含 1,则将其左子树置为 null。
如果它的右子树不包含 1,则将其右子树置为 null。
如果当前节点是叶子节点且值为 0,则返回 null,表示需要剪枝。
最终返回修剪后的二叉树。
public TreeNode pruneTree(TreeNode root) {
return containsOne(root) ? root : null;
}
private boolean containsOne(TreeNode node) {
if (node == null) {
return false;
}
// 递归检查左子树是否包含 1
boolean leftContainsOne = containsOne(node.left);
// 递归检查右子树是否包含 1
boolean rightContainsOne = containsOne(node.right);
// 如果左子树不包含 1,则剪枝
if (!leftContainsOne) {
node.left = null;
}
// 如果右子树不包含 1,则剪枝
if (!rightContainsOne) {
node.right = null;
}
// 如果当前节点是 1,或者左子树或右子树包含 1,则返回 true
return node.val == 1 || leftContainsOne || rightContainsOne;
}
递归函数的写法:
1、确定递归函数的参数和返回值:确定哪些参数是递归过程中需要处理的,那么就在递归函数里加上这个参数,并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
2、确定终止条件:写完了递归算法,运行的时候,经常会出现栈溢出的错误,就是没写终止条件,或者终止条件不对,操作系统也是用一个栈结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈就会溢出。
3、确定单层递归的逻辑,确定每一层递归需要处理的信息,在这里也就会重复调用自己来实现递归过程。
leetcode上二叉树的建树测试代码
typedef int ElemType;
struct TreeNode
{
struct TreeNode* lchild;
struct TreeNode* rchild;
ElemType val;
TreeNode(ElemType x) : val(x), lchild(NULL), rchild(NULL) { }
};
TreeNode* createBinaryTree(TreeNode* root, ElemType x) {
if (!root) {
root = new TreeNode(x);
return root;
}
if (root->val > x) {
root->lchild = createBinaryTree(root->lchild, x);
}
if (root->val < x) {
root->rchild = createBinaryTree(root->rchild, x);
}
return root;
}
TreeNode* levelCreateTree(vector<ElemType> vec) {
if (vec.size() == 0) return NULL;
queue<TreeNode*> que;
TreeNode* root = new TreeNode(vec[0]);
que.push(root);
int cnt = 0;
while (!que.empty()) {
TreeNode* tmp = que.front();
que.pop();
if (++cnt < vec.size()) {
tmp->lchild = new TreeNode(vec[cnt]);
que.push(tmp->lchild);
}
if (++cnt < vec.size()) {
tmp->rchild = new TreeNode(vec[cnt]);
que.push(tmp->rchild);
}
}
return root;
}
void PreOrder(TreeNode* root) {
if (!root) return;
cout << root->val << " ";
PreOrder(root->lchild);
PreOrder(root->rchild);
}
void InOrder(TreeNode* root) {
if (!root) return;
InOrder(root->lchild);
cout << root->val << " ";
InOrder(root->rchild);
}
Java代码如下:
package test3;
import java.util.ArrayDeque;
import java.util.Queue;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public class BinaryTree {
public static void inorderTraversal(TreeNode root) {
if (root == null) return;
inorderTraversal(root.left);
System.out.print(root.val + " ");
inorderTraversal(root.right);
}
public static TreeNode levelCreateTree(int[] nums) {
Queue<TreeNode> queue = new ArrayDeque<>();
TreeNode root = new TreeNode(nums[0]);
queue.add(root);
int cnt = 0;
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (++cnt < nums.length) {
if (nums[cnt] != Integer.MIN_VALUE) {
node.left = new TreeNode(nums[cnt]);
queue.add(node.left);
} else {
node.left = null;
}
}
if (++cnt < nums.length) {
if (nums[cnt] != Integer.MIN_VALUE) {
node.right = new TreeNode(nums[cnt]);
queue.add(node.right);
} else {
node.right = null;
}
}
}
return root;
}
private static void createTree(TreeNode root, int[] nums, int i) {
int leftIndex = 2 * i + 1;
int rightIndex = 2 * i + 2;
if (leftIndex < nums.length) {
if (nums[leftIndex] != Integer.MIN_VALUE) {
root.left = new TreeNode(nums[leftIndex]);
createTree(root.left, nums, leftIndex);
} else {
root.left = null;
}
}
if (rightIndex < nums.length) {
if (nums[rightIndex] != Integer.MIN_VALUE) {
root.right = new TreeNode(nums[rightIndex]);
createTree(root.right, nums, rightIndex);
} else {
root.right = null;
}
}
}
public static TreeNode recrusionCreateTree(int[] nums) {
TreeNode root = new TreeNode(nums[0]);
createTree(root, nums, 0);
return root;
}
public static void main(String[] args) {
int[] nums = {-10,9,20,Integer.MIN_VALUE,Integer.MIN_VALUE,15,7};
// TreeNode treeNode = BinaryTree.levelCreateTree(nums);
TreeNode treeNode = recrusionCreateTree(nums);
BinaryTree.inorderTraversal(treeNode);
}
}
leetcode 94 二叉树的中序遍历
递归算法
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
void traversal(TreeNode* root, vector<int>& result)
{
if(root == nullptr)
{
return;
}
traversal(root->left, result);
result.push_back(root->val);
traversal(root->right, result);
}
};
非递归算法
1、沿着根节点的左孩子,依次入栈,直到左孩子为空,说明已经找到可以输出的结点。
2、栈顶元素出栈并访问,若其右孩子为空,则继续执行2,若其右孩子不空,将右子树转执行1。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> sck;
TreeNode* ptr = root; //ptr为二叉树的遍历指针
while(!sck.empty() || ptr != nullptr)
{
if(ptr != nullptr)
{
sck.push(ptr);
ptr = ptr->left;
}
else
{
ptr = sck.top();
sck.pop();
result.push_back(ptr->val);
ptr = ptr->right;
}
}
return result;
}
};
leetcode 144 二叉树的前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> sck;
vector<int> result;
TreeNode* ptr = root;
while(!sck.empty() || ptr != nullptr)
{
if(ptr != nullptr)
{
sck.push(ptr);
result.push_back(ptr->val);
ptr = ptr->left;
}
else
{
ptr = sck.top();
sck.pop();
ptr = ptr->right;
}
}
return result;
}
};
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> sck;
vector<int> result;
if(root == nullptr) return result;
sck.push(root);
while(!sck.empty())
{
TreeNode* tmp = sck.top();
sck.pop();
result.push_back(tmp->val);
if(tmp->right) sck.push(tmp->right);
if(tmp->left) sck.push(tmp->left);
}
return result;
}
};
leetcode 145 二叉树的后序遍历
二叉树的前序遍历是根左右,而后续遍历是左右根,只需将前序遍历代码修改一下,改成根右左的遍历方式,最后再逆转一下结果就是后序遍历结果了。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> sck;
vector<int> result;
if(root == nullptr) return result;
sck.push(root);
while(!sck.empty())
{
TreeNode* tmp = sck.top();
sck.pop();
result.push_back(tmp->val);
if(tmp->left) sck.push(tmp->left);
if(tmp->right) sck.push(tmp->right);
}
reverse(result.begin(), result.end());
return result;
}
};
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> sck1;
stack<TreeNode*> sck2;
if(root != nullptr) sck1.push(root);
while(!sck1.empty())
{
TreeNode* tmpNode = sck1.top();
sck1.pop();
sck2.push(tmpNode);
if(tmpNode->left) sck1.push(tmpNode->left);
if(tmpNode->right) sck1.push(tmpNode->right);
}
while(!sck2.empty())
{
TreeNode* tmpNode = sck2.top();
result.push_back(tmpNode->val);
sck2.pop();
}
return result;
}
};
/**
* 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> postorderTraversal(TreeNode* root) {
TreeNode* p = root;
TreeNode* pre = NULL;
stack<TreeNode*> sck;
vector<int> result;
while (p || !sck.empty()) {
if (p) {
sck.push(p);
p = p->left;
}
else {
p = sck.top();
if (p->right && p->right != pre) {
p = p->right; //直接将处理节点转向右子树的根节点,节点p不弹出栈
}
else {
TreeNode* tmp = sck.top();
sck.pop();
result.push_back(tmp->val);
pre = p;
p = NULL; //后序遍历,左右根,左子树,右子树已经压栈处理完毕,这里工作指针p置空,继续弹栈处理栈中其他元素
}
}
}
return result;
}
};
leetcode 102 二叉树的层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root == NULL) return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
vector<int> vec;
//这里需要使用固定大小的size,因为que.size()在下面for循环中是不断变化的
for(int i = 0; i < size; i++)
{
TreeNode* tmp = que.front();
que.pop();
vec.push_back(tmp->val);
if(tmp->left != NULL) que.push(tmp->left);
if(tmp->right != NULL) que.push(tmp->right);
}
result.push_back(vec);
}
return result;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) {
return result;
}
// 使用队列实现 BFS
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root); // 将根节点加入队列
while (!queue.isEmpty()) {
int levelSize = queue.size(); // 当前层的节点数量
List<Integer> currentLevel = new ArrayList<>(); // 当前层的节点值
// 遍历当前层的所有节点
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll(); // 取出队首节点
currentLevel.add(node.val); // 将节点值加入当前层列表
// 将子节点加入队列
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
// 将当前层的节点值加入结果列表
result.add(currentLevel);
}
return result;
}
}
leetcode 107 二叉树的层序遍历II
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
stack<vector<int>> sck;
if(root == nullptr)
return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
vector<int> vec;
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
vec.push_back(tmpNode->val);
if(tmpNode->left) que.push(tmpNode->left);
if(tmpNode->right) que.push(tmpNode->right);
}
sck.push(vec);
}
while(!sck.empty()) //这里也可以用reverse函数解决
{
result.push_back(sck.top());
sck.pop();
}
return result;
}
};
leetcode 119 二叉树的右视图
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root == nullptr)
return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
vector<int> vec;
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
vec.push_back(tmpNode->val);
if(tmpNode->left != nullptr) que.push(tmpNode->left);
if(tmpNode->right != nullptr) que.push(tmpNode->right);
}
result.push_back(vec.back());
}
return result;
}
};
leetcode 637 二叉树的层平均值
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> result;
queue<TreeNode*> que;
if(root == nullptr)
return result;
que.push(root);
while(!que.empty())
{
vector<int> vec;
int size = que.size();
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
vec.push_back(tmpNode->val);
if(tmpNode->left != nullptr) que.push(tmpNode->left);
if(tmpNode->right != nullptr) que.push(tmpNode->right);
}
result.push_back(countAver(vec));
}
return result;
}
double countAver(vector<int> vec)
{
long sum = 0;
for(int i = 0; i < vec.size(); i++)
{
sum += vec[i];
}
double value = (double) sum / (double) vec.size();
return value;
}
};
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> result;
queue<TreeNode*> que;
if(root == nullptr)
return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
double sum = 0;
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
sum += tmpNode->val;
if(tmpNode->left != nullptr) que.push(tmpNode->left);
if(tmpNode->right != nullptr) que.push(tmpNode->right);
}
result.push_back(sum / size);
}
return result;
}
};
leetcode 429 N叉树的层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> result;
queue<Node*> que;
if(root == NULL)
return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
vector<int> vec;
for(int i = 0; i < size; i++)
{
Node* tmp = que.front();
que.pop();
vec.push_back(tmp->val);
for(int j = 0; j < tmp->children.size(); j++)
{
que.push(tmp->children[j]);
}
}
result.push_back(vec);
}
return result;
}
};
leetcode 515 在每个树行中找到最大值
#define INT_MIN 0x80000000
#define INT_MAX 0x7fffffff
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root == NULL) return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
vector<int> vec;
//这里需要使用固定大小的size,因为que.size()在下面for循环中是不断变化的
for(int i = 0; i < size; i++)
{
TreeNode* tmp = que.front();
que.pop();
vec.push_back(tmp->val);
if(tmp->left != NULL) que.push(tmp->left);
if(tmp->right != NULL) que.push(tmp->right);
}
result.push_back(getMaxValue(vec));
}
return result;
}
int getMaxValue(vector<int> vec)
{
int min = INT_MIN;
int index = 0;
for(int i = 0; i < vec.size(); i++)
{
if(vec[i] > min)
{
min = vec[i];
index = i;
}
}
return vec[index];
}
};
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root == NULL) return result;
que.push(root);
while(!que.empty())
{
int size = que.size();
int maxValue = INT_MIN;
for(int i = 0; i < size; i++)
{
TreeNode* tmp = que.front();
que.pop();
maxValue = tmp->val > maxValue ? tmp->val : maxValue;
if(tmp->left != NULL) que.push(tmp->left);
if(tmp->right != NULL) que.push(tmp->right);
}
result.push_back(maxValue);
}
return result;
}
};
leetcode 116 填充每个节点的下一个右侧节点指针
class Solution {
public:
Node* connect(Node* root) {
if(root == NULL)
return NULL;
queue<Node*> que;
que.push(root);
while(!que.empty())
{
int size = que.size();
for(int i = 0; i < size; i++)
{
Node* tmpNode = que.front();
que.pop();
if(i < size - 1)
{
Node* aftertmp = que.front();
tmpNode->next = aftertmp;
}
else
{
tmpNode->next = NULL;
}
if(tmpNode->left != NULL) que.push(tmpNode->left);
if(tmpNode->right != NULL) que.push(tmpNode->right);
}
}
return root;
}
};
leetcode 117 填充每个节点的下一个右侧节点指针II
同 116 code
leetcode 104 二叉树的最大深度
后序遍历求根节点高度的递归
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == NULL)
return 0;
int leftHigh = maxDepth(root->left);
int rightHigh = maxDepth(root->right);
return 1 + max(leftHigh, rightHigh);
}
};
前序遍历求深度的递归(有点像回溯)
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == NULL)
return 0;
int result = 0;
backtracking(root, result, 1);
return result;
}
void backtracking(TreeNode* root, int& result, int depth)
{
if(root == NULL)
return;
result = result > depth ? result : depth;
if(root->left) backtracking(root->left, result, depth+1);
if(root->right) backtracking(root->right, result, depth+1);
}
};
层序遍历求高度
class Solution {
public:
int maxDepth(TreeNode* root) {
int depth = 0;
queue<TreeNode*> que;
if(root == nullptr)
return depth;
que.push(root);
while(!que.empty())
{
depth++;
int size = que.size();
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
if(tmpNode->left) que.push(tmpNode->left);
if(tmpNode->right) que.push(tmpNode->right);
}
}
return depth;
}
};
leetcode 559 N叉树的最大深度
递归逻辑
class Solution {
public:
int maxDepth(Node* root) {
if(root == NULL)
return 0;
int depth = 0;
for(int i = 0; i < root->children.size(); i++)
{
depth = max(depth, maxDepth(root->children[i]));
}
return depth + 1;
}
};
迭代逻辑
class Solution {
public:
int maxDepth(Node* root) {
int depth = 0;
queue<Node*> que;
if(root != nullptr) que.push(root);
while(!que.empty())
{
depth++;
int size = que.size();
for(int i = 0; i < size; i++)
{
Node* tmpNode = que.front();
que.pop();
for(int i = 0; i < tmpNode->children.size(); i++)
{
if(tmpNode->children[i]) que.push(tmpNode->children[i]);
}
}
}
return depth;
}
};
leetcode 111 二叉树的最小深度
后续遍历逻辑求根结点最小高度
class Solution {
public:
int minDepth(TreeNode* root) {
return getMinDepth(root);
}
int getMinDepth(TreeNode* root)
{
if(root == NULL) return 0;
int leftHigh = getMinDepth(root->left);
int rightHigh = getMinDepth(root->right);
if(root->left != NULL && root->right == NULL)
{
return 1 + leftHigh;
}
if(root->left == NULL && root->right != NULL)
{
return 1 + rightHigh;
}
return 1 + min(rightHigh, leftHigh);
}
};
前序遍历逻辑求最小深度
class Solution {
public:
int minDepth(TreeNode* root) {
int result = INT_MAX;
backtracking(root, result, 1);
return result == INT_MAX ? 0 : result;
}
void backtracking(TreeNode* root, int& result, int depth) {
if (root == NULL) return;
if (!root->left && !root->right) result = min(result, depth);
if (root->left) backtracking(root->left, result, depth+1);
if (root->right) backtracking(root->right, result, depth+1);
}
};
层序遍历逻辑
class Solution {
public:
int minDepth(TreeNode* root) {
int depth = 0;
queue<TreeNode*> que;
if(root == nullptr)
return depth;
que.push(root);
bool flag = false;
while(!que.empty())
{
depth++;
int size = que.size();
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
if(tmpNode->left) que.push(tmpNode->left);
if(tmpNode->right) que.push(tmpNode->right);
if(tmpNode->left == nullptr && tmpNode->right == nullptr)
{
flag = true;
}
}
if(flag) break;
}
return depth;
}
};
leetcode 226 翻转二叉树
递归算法
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root == NULL)
return root;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
非递归算法(用栈模拟深度优先遍历)
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> sck;
TreeNode* ptr = root;
while(!sck.empty() || ptr != NULL)
{
if(ptr != NULL)
{
swap(ptr->left, ptr->right);
sck.push(ptr);
ptr = ptr->left;
}
else
{
TreeNode* tmpNode = sck.top();
sck.pop();
ptr = tmpNode->right;
}
}
return root;
}
};
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> sck;
if(root == NULL)
return root;
TreeNode* ptr = root;
sck.push(ptr);
while(!sck.empty())
{
TreeNode* tmpNode = sck.top();
sck.pop();
swap(tmpNode->left, tmpNode->right);
if(tmpNode->right != NULL) sck.push(tmpNode->right);
if(tmpNode->left != NULL) sck.push(tmpNode->left);
}
return root;
}
};
广度优先遍历(层序遍历)
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root == NULL)
return root;
queue<TreeNode*> que;
que.push(root);
while(!que.empty())
{
int size = que.size();
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
swap(tmpNode->left, tmpNode->right);
if(tmpNode->left != NULL) que.push(tmpNode->left);
if(tmpNode->right != NULL) que.push(tmpNode->right);
}
}
return root;
}
};
leetcode 101 对称二叉树
有关于对称二叉树进行比较时要比较的不是左右节点,而是根节点的左右子树是不是翻转的,所以其实我们要比较的两个树,这两个树是根节点的左右子树,所以在递归遍历过程中要同时遍历两颗树。我们需要比较的是两个子树的里侧和外侧的元素是否相等。对于该题的遍历顺序只能是后序遍历,因为我们需要递归函数的返回值来判断两个子树的内侧和外侧节点是否相等。正是因为要遍历两颗树,而且要比较内侧和外侧的节点,所以准确来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(root == NULL) return true;
return afterTraversal(root->left, root->right);
}
bool afterTraversal(TreeNode* left, TreeNode* right)
{
if(left == NULL && right != NULL) return false;
else if(left != NULL && right == NULL) return false;
else if(left == NULL && right == NULL) return true;
else if(left->val != right->val) return false;
//此时就是左右节点都不为空,并且数值相等的情况
bool outside = afterTraversal(left->left, right->right); //左右子树的外侧节点相等
bool inside = afterTraversal(left->right, right->left); //左右子树的内侧节点相等
bool isSame = outside && inside; //采用后续遍历的方式判断最终结果
return isSame;
}
};
使用队列来判断根节点的左子树和右子树的内侧和外侧是否相等。
迭代法其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么使用栈也是OK的,只需要将下列代码中的队列改成栈就行了。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(root == NULL) return true;
queue<TreeNode*> que;
que.push(root->left);
que.push(root->right);
while(!que.empty())
{
TreeNode* leftNode = que.front();
que.pop();
TreeNode* rightNode = que.front();
que.pop();
if(!leftNode && !rightNode)
{
continue;
}
if(!leftNode || !rightNode || (leftNode->val != rightNode->val))
{
return false;
}
que.push(leftNode->left);
que.push(rightNode->right);
que.push(leftNode->right);
que.push(rightNode->left);
}
return true;
}
};
leetcode 100 相同的树
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p == NULL && q == NULL) return true;
else if(p == NULL && q != NULL) return false;
else if(p != NULL && q == NULL) return false;
else if(p->val != q->val) return false;
bool leftSame = isSameTree(p->left, q->left);
bool rightSame = isSameTree(p->right, q->right);
bool isSame = leftSame && rightSame;
return isSame;
}
};
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
queue<TreeNode*> que;
que.push(p);
que.push(q);
while(!que.empty())
{
TreeNode* firstNode = que.front();
que.pop();
TreeNode* secondNode = que.front();
que.pop();
if(!firstNode && !secondNode)
{
continue;
}
if(!firstNode || !secondNode || (firstNode->val != secondNode->val))
{
return false;
}
que.push(firstNode->left);
que.push(secondNode->left);
que.push(firstNode->right);
que.push(secondNode->right);
}
return true;
}
};
leetcode 572 另一颗树的子树
一个树是另一个树的子树 则
1、要么这两个树相等
2、要么这个树是左树的子树
3、要么这个树是右树的子树
这三者之间是或的关系
另外注意该题的terminate条件
class Solution {
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root == NULL && subRoot == NULL) return true;
if(root == NULL && subRoot != NULL) return false;
return isSameTree(root, subRoot) || isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p == NULL && q == NULL) return true;
else if(p == NULL && q != NULL) return false;
else if(p != NULL && q == NULL) return false;
else if(p->val != q->val) return false;
bool leftSame = isSameTree(p->left, q->left);
bool rightSame = isSameTree(p->right, q->right);
bool isSame = leftSame && rightSame;
return isSame;
}
};
leetcode 222 完全二叉树的节点个数
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == NULL) return 0;
int leftNum = countNodes(root->left);
int rightNum = countNodes(root->right);
return 1 + leftNum + rightNum;
}
};
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == NULL) return 0;
queue<TreeNode*> que;
que.push(root);
int num = 0;
while(!que.empty())
{
TreeNode* tmpNode = que.front();
que.pop();
num++;
if(tmpNode->left) que.push(tmpNode->left);
if(tmpNode->right) que.push(tmpNode->right);
}
return num;
}
};
leetcode 110 平衡二叉树
class Solution {
public:
bool isBalanced(TreeNode* root) {
bool flag = true;
getHigh(root, flag);
return flag;
}
int getHigh(TreeNode* root, bool& flag)
{
if(root == NULL) return 0;
int leftHigh = getHigh(root->left, flag);
int rightHigh = getHigh(root->right, flag);
if(abs(leftHigh - rightHigh) > 1)
{
flag = false;
}
return 1 + max(leftHigh, rightHigh);
}
};
leetcode 563 二叉树的坡度
class Solution {
public:
int result = 0;
int Traverse(TreeNode* root) { //选用后序遍历策略,先对结点的左右子树计算
if (root == NULL) {
return 0;
}
int leftVal = Traverse(root->left); //计算root的左子树的节点value和
int rightVal = Traverse(root->right); //计算root的右子树的节点value和
result += abs(leftVal - rightVal);
return leftVal + rightVal + root->val; //返回以root为根的所有节点的value和
}
int findTilt(TreeNode* root) {
Traverse(root);
return result;
}
};
leetcode 543 二叉树的直径
class Solution {
public:
int res = 0;
int getDepth(TreeNode* root) {
if (root == NULL) {
return 0;
}
int left = getDepth(root->left);
int right = getDepth(root->right);
res = max(res, left + right); //二叉树的直径:即二叉树的结点的左右子树的深度之和的最大值
return max(left, right) + 1;
}
int diameterOfBinaryTree(TreeNode* root) {
getDepth(root);
return res;
}
};
leetcode 538 把二叉搜索树转换为累加树
class Solution {
public:
int res = 0;
TreeNode* convertBST(TreeNode* root) {
if (root == NULL) {
return 0;
}
convertBST(root->right);
res = res + root->val;
root->val = res;
convertBST(root->left);
return root;
}
};
class Solution {
public:
TreeNode* convertBST(TreeNode* root) {
stack<TreeNode*> sck;
int pre = 0;
TreeNode* cur = root; //这里要设置一个遍历指针,保存root,如果直接用root去遍历,最后root为空了
while(!sck.empty() || cur != NULL)
{
if(cur)
{
sck.push(cur);
cur = cur->right;
}
else
{
TreeNode* tmpNode = sck.top();
sck.pop();
tmpNode->val += pre;
pre = tmpNode->val;
cur = tmpNode->left;
}
}
return root;
}
};
leetcode 404 左叶子之和
左叶子:如果左节点不为空,且左节点没有左右孩子,那么这个节点就是左叶子
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
int sum = 0;
recursiveFunc(sum, root);
return sum;
}
void recursiveFunc(int& sum, TreeNode* node)
{
if(node->left != NULL && node->left->left == NULL && node->left->right == NULL)
{
sum += node->left->val; //左叶子
}
if(node->left != NULL) recursiveFunc(sum, node->left);
if(node->right != NULL) recursiveFunc(sum, node->right);
}
};
前序迭代策略
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
int sum = 0;
if(root == NULL) return sum;
stack<TreeNode*> sck;
while(!sck.empty() || root != NULL)
{
if(root)
{
if(root->left != NULL && root->left->left == NULL && root->left->right == NULL)
{
sum += root->left->val;
}
sck.push(root);
root = root->left;
}
else
{
TreeNode* tmpNode = sck.top();
sck.pop();
root = tmpNode->right;
}
}
return sum;
}
};
leetcode 513 找树左下角的值
层序遍历
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
que.push(root);
vector<vector<int>> result;
while(!que.empty())
{
vector<int> vec;
int size = que.size();
for(int i = 0; i < size; i++)
{
TreeNode* tmpNode = que.front();
que.pop();
vec.push_back(tmpNode->val);
if(tmpNode->left) que.push(tmpNode->left);
if(tmpNode->right) que.push(tmpNode->right);
}
result.push_back(vec);
}
return result[result.size()-1][0];
}
};
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
recursiveFunc(root, 1);
return value;
}
void recursiveFunc(TreeNode* root, int depth)
{
if(root->left == NULL && root->right == NULL)
{
if(depth > maxdepth)
{
maxdepth = depth;
value = root->val;
}
}
if(root->left != NULL) recursiveFunc(root->left, depth + 1);
if(root->right != NULL) recursiveFunc(root->right, depth + 1);
}
public:
int maxdepth = INT_MIN;
int value;
};
leetcode 257 二叉树的所有路径
回溯策略
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
string path;
if(root == NULL) return result;
path = path + to_string(root->val) + "->";
backtracking(result, path, root);
return result;
}
void backtracking(vector<string>& result, string& path, TreeNode* root)
{
if(root->left == NULL && root->right == NULL) //terminate
{
path.pop_back();
path.pop_back();
result.push_back(path);
return;
}
if(root->left != NULL)
{
string pathBak = path;
path = path + to_string(root->left->val) + "->";
backtracking(result, path, root->left);
path = pathBak;
}
if(root->right != NULL)
{
string pathBak = path;
path = path + to_string(root->right->val) + "->";
backtracking(result, path, root->right);
path = pathBak;
}
}
};
回溯策略精简版本
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
string path;
if(root == NULL) return result;
backtracking(result, path, root);
return result;
}
void backtracking(vector<string>& result, string path, TreeNode* root)
{
path = path + to_string(root->val);
if(root->left == NULL && root->right == NULL) //terminate
{
result.push_back(path);
return;
}
if(root->left != NULL) backtracking(result, path + "->", root->left);
if(root->right != NULL) backtracking(result, path + "->", root->right);
}
};
迭代法模拟前序遍历顺序实现
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
if(root == NULL) return result;
stack<TreeNode*> sck1;
stack<string> sck2;
sck1.push(root);
sck2.push(to_string(root->val));
while(!sck1.empty())
{
TreeNode* tmpNode = sck1.top();
sck1.pop();
string path = sck2.top();
sck2.pop();
if(tmpNode->left == NULL && tmpNode->right == NULL)
{
result.push_back(path);
}
if(tmpNode->right != NULL)
{
sck1.push(tmpNode->right);
sck2.push(path + "->" + to_string(tmpNode->right->val));
}
if(tmpNode->left != NULL)
{
sck1.push(tmpNode->left);
sck2.push(path + "->" + to_string(tmpNode->left->val));
}
}
return result;
}
};
leetcode 112 路径总和
递归函数什么时候需要返回值?什么时候不需要返回值?
1、如果需要搜索整颗二叉树且不用处理递归返回结果,递归函数就不需要返回值。
2、如果需要搜索整颗二叉树且需要处理递归返回结果,递归函数就需要返回值。
3、如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径需要即时返回。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == NULL) return false;
return backtracking(root, targetSum - root->val);
}
bool backtracking(TreeNode* root, int targetSum)
{
if(root->left == NULL && root->right == NULL && targetSum == 0) return true;
if(root->left == NULL && root->right == NULL && targetSum != 0) return false;
if(root->left)
{
if(backtracking(root->left, targetSum - root->left->val))
{
return true;
}
}
if(root->right)
{
if(backtracking(root->right, targetSum - root->right->val))
{
return true;
}
}
return false;
}
};
DFS代码
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == NULL) return false;
return backtracking(root, root->val, targetSum);
}
bool backtracking(TreeNode* root, int total, int targetSum) {
if (!root->left && !root->right && total == targetSum) { //找到叶子结点,并且路径总和符合要求
return true;
}
bool l = false;
bool r = false;
if (root->left) {
l = backtracking(root->left, total + root->left->val, targetSum);
}
if (root->right) {
r = backtracking(root->right, total + root->right->val, targetSum);
}
return l || r;
}
};
栈模拟递归
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == NULL) return false;
stack<pair<TreeNode*, int>> sck;
sck.push(pair<TreeNode*, int>(root, targetSum - root->val));
bool flag = false;
while(!sck.empty())
{
pair<TreeNode*, int> node = sck.top();
sck.pop();
if(!node.first->left && !node.first->right && node.second == 0)
{
flag = true;
return flag;
}
if(node.first->right != NULL)
sck.push(pair<TreeNode*, int>(node.first->right, node.second - node.first->right->val));
if(node.first->left != NULL)
sck.push(pair<TreeNode*, int>(node.first->left, node.second - node.first->left->val));
}
return flag;
}
};
leetcode 113 路径总和II
class Solution {
public:
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> result;
vector<int> path;
if(!root) return result;
path.push_back(root->val);
backtracking(result, path, root, targetSum - root->val);
return result;
}
void backtracking(vector<vector<int>>& result, vector<int>& path, TreeNode* root, int targetSum)
{
if(!root->left && !root->right && targetSum == 0)
{
result.push_back(path);
}
if(root->left)
{
path.push_back(root->left->val);
backtracking(result, path, root->left, targetSum - root->left->val);
path.pop_back();
}
if(root->right)
{
path.push_back(root->right->val);
backtracking(result, path, root->right, targetSum - root->right->val);
path.pop_back();
}
}
};
leetcode 437 路径总和III
class Solution {
public:
// int rootSum(TreeNode* root, long targetSum) {
// if (root == NULL) {
// return 0;
// }
// targetSum = targetSum - root->val;
// if (targetSum == 0) {
// return 1 + rootSum(root->left, targetSum) + rootSum(root->right, targetSum);
// }
// else {
// return rootSum(root->left, targetSum) + rootSum(root->right, targetSum);
// }
// }
int rootSum(TreeNode* root, long targetSum) {
if (root == NULL) {
return 0;
}
int ret = 0;
if (root->val == targetSum) { //说明找到了一条路径
ret++;
}
//以root->left为根节点,targetSum - val为寻找的路径和,继续寻找路径
ret += rootSum(root->left, targetSum - root->val);
//以root->right为根节点,targetSum - val为寻找的路径和,继续寻找路径
ret += rootSum(root->right, targetSum - root->val);
return ret;
}
int pathSum(TreeNode* root, int targetSum) {
if (root == NULL) {
return 0;
}
int ret = rootSum(root, targetSum); //以root为根节点的树中寻找路径
ret += pathSum(root->left, targetSum); //递归左子树,在左子树中寻找路径
ret += pathSum(root->right, targetSum); //递归右子树,在左子树中寻找路径
return ret;
}
};
leetcode 124 二叉树中的最大路径和
class Solution {
public:
int result = INT_MIN;
int maxPathSum(TreeNode* root) {
DFS(root);
return result;
}
int DFS(TreeNode* root) { // 函数功能:返回当前子树能为parent node提供的最大的value
if (root == NULL) return 0;
int leftValue = DFS(root->left);
int rightValue = DFS(root->right);
result = max(result, root->val + leftValue + rightValue); //不断更新最终结果的最大值max
int Value = max(root->val + leftValue, root->val + rightValue); //返回当前子树结点能为parent提供的最大Value
return Value < 0 ? 0 : Value; //如果该子树累计提供的Value小于0,则返回0表示该子树不被考虑放入路径
}
};
leetcode 617 合并二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root1 == NULL) return root2;
if(root2 == NULL) return root1;
TreeNode* root = new TreeNode();
root->val = root1->val + root2->val;
root->left = mergeTrees(root1->left, root2->left);
root->right = mergeTrees(root1->right, root2->right);
return root;
}
};
leetcode 700 二叉搜索树中的搜索
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root == NULL || root->val == val)
return root;
if(root->val > val) return searchBST(root->left, val);
if(root->val < val) return searchBST(root->right, val);
return NULL;
}
};
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while(root)
{
if(root->val == val) return root;
else if(root->val < val) root = root->right;
else root = root->left;
}
return NULL;
}
};
leetcode 98 验证二叉搜索树
需要注意,不能单纯的比较左节点小于中间节点,右节点大于中间节点,而是左子树都小于中间节点,右子树都大于中间节点。
if (root->val > root->left->val && root->val < root->right->val) { //错误写法
return true;
else
return false;
class Solution {
TreeNode* pre = NULL;
public:
bool isValidBST(TreeNode* root) {
if(root == NULL) return true;
bool left = isValidBST(root->left);
if(pre != NULL && pre->val >= root->val)
{
return false;
}
pre = root;
bool right = isValidBST(root->right);
return left && right;
}
};
class Solution {
public:
bool isValidBST(TreeNode* root) {
vector<int> result;
traversal(root, result);
bool flag = true;
for(int i = 0; i < result.size() - 1; i++)
if(result[i] >= result[i+1])
flag = false;
return flag;
}
void traversal(TreeNode* root, vector<int>& result)
{
if(root == NULL) return;
traversal(root->left, result);
result.push_back(root->val);
traversal(root->right, result);
}
};
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> sck;
TreeNode* pre = NULL;
bool flag = true;
while(!sck.empty() || root != NULL)
{
if(root)
{
sck.push(root);
root = root->left;
}
else
{
TreeNode* tmpNode = sck.top();
sck.pop();
if(pre != NULL && pre->val >= tmpNode->val)
{
flag = false;
return flag;
}
pre = tmpNode;
root = tmpNode->right;
}
}
return flag;
}
};
leetcode 958 二叉树的完全性检验
class Solution {
public:
bool isCompleteTree(TreeNode* root) {
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
auto tmp = que.front();
que.pop();
if (tmp != NULL) {
que.push(tmp->left);
que.push(tmp->right);
}
else {
while (!que.empty()) {
TreeNode* p = que.front();
que.pop();
if (p != NULL) {
return false;
}
}
}
}
return true;
}
};
leetcode 530 二叉搜索树的最小绝对差
class Solution {
public:
int getMinimumDifference(TreeNode* root) {
int min = INT_MAX;
vector<int> result;
traversal(root, result);
for(int i = 0; i < result.size()-1; i++)
{
int diff = result[i+1] - result[i];
if(diff < min)
min = diff;
}
return min;
}
void traversal(TreeNode* root, vector<int>& result)
{
if(root == NULL) return;
traversal(root->left, result);
result.push_back(root->val);
traversal(root->right, result);
}
};
class Solution {
int min = INT_MAX;
TreeNode* pre = NULL;
public:
int getMinimumDifference(TreeNode* root) {
traversal(root);
return min;
}
void traversal(TreeNode* root)
{
if(root == NULL) return;
traversal(root->left);
if(pre != NULL)
{
int diff = root->val - pre->val;
if(diff < min) min = diff;
}
pre = root;
traversal(root->right);
}
};
class Solution {
int min = INT_MAX;
TreeNode* pre = NULL;
public:
int getMinimumDifference(TreeNode* root) {
stack<TreeNode*> sck;
while(!sck.empty() || root != NULL)
{
if(root)
{
sck.push(root);
root = root->left;
}
else
{
TreeNode* tmpNode = sck.top();
sck.pop();
if(pre != NULL)
{
int diff = tmpNode->val - pre->val;
if(diff < min) min = diff;
}
pre = tmpNode;
root = tmpNode->right;
}
}
return min;
}
};
leetcode 501 二叉搜索树中的众数
class Solution {
unordered_map<int, int> umap;
public:
static bool cmp(const pair<int, int>& a, const pair<int, int>& b)
{
return a.second > b.second;
}
vector<int> findMode(TreeNode* root) {
vector<int> result;
if(root == NULL) return result;
traversal(root);
vector<pair<int, int>> vec(umap.begin(), umap.end());
sort(vec.begin(), vec.end(), cmp);
result.push_back(vec[0].first);
for(int i = 1; i < vec.size(); i++)
{
if(vec[0].second == vec[i].second) result.push_back(vec[i].first);
else break;
}
return result;
}
void traversal(TreeNode* root)
{
if(root == NULL) return;
traversal(root->left);
umap[root->val]++;
traversal(root->right);
}
};
class Solution {
unordered_map<int, int> umap;
public:
vector<int> findMode(TreeNode* root) {
vector<int> result;
if(root == NULL) return result;
traversal(root);
int cnt = INT_MIN;
for(auto it : umap)
{
if(it.second > cnt) cnt = it.second;
}
for(auto it : umap)
{
if(it.second == cnt)
{
result.push_back(it.first);
}
}
return result;
}
void traversal(TreeNode* root)
{
if(root == NULL) return;
traversal(root->left);
umap[root->val]++;
traversal(root->right);
}
};
只需要遍历一遍的方案
class Solution {
int maxCount = 0;
int count = 0;
vector<int> result;
TreeNode* pre = NULL;
public:
vector<int> findMode(TreeNode* root) {
traversal(root);
return result;
}
void traversal(TreeNode* root)
{
if(root == NULL) return;
traversal(root->left);
if(pre == NULL) count = 1;
else if(root->val == pre->val) count++;
else count = 1;
pre = root;
if(count == maxCount) result.push_back(root->val);
if(count > maxCount)
{
maxCount = count;
result.clear();
result.push_back(root->val);
}
traversal(root->right);
}
};
leetcode 236 二叉树的最近公共祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
vector<int> result1;
vector<int> result2;
vector<int> path;
bool finish = false;
backtracking(result1, path, root, p, finish);
path.clear();
finish = false;
backtracking(result2, path, root, q, finish);
int i;
for(i = 0; i < result1.size() && i < result2.size(); i++)
{
if(result1[i] == result2[i]) continue;
else break;
}
return searchNode(root, result1[i-1]);
}
TreeNode* searchNode(TreeNode* root, int value)
{
if (!root) return NULL;
if (root->val == value) return root;
TreeNode* left = searchNode(root->left, value);
TreeNode* right = searchNode(root->right, value);
return left != NULL ? left : right;
}
void backtracking(vector<int>& result, vector<int>& path, TreeNode* root, TreeNode* ptr, bool& finish)
{
if (!root || finish) return;
if (root->val == ptr->val)
{
path.push_back(root->val);
finish = true;
result = path;
}
path.push_back(root->val);
backtracking(result, path, root->left, ptr, finish);
backtracking(result, path, root->right, ptr, finish);
path.pop_back();
}
};
//采用后序遍历回溯的思想,从底向上进行遍历
//如何判断一个节点是节点q和节点p的公共祖先?
//如果找到一个节点,发现左子树出现节点p(或q),右子树出现节点q(或p),那么该节点就是p和q的最近公共祖先
//本题有返回值,回溯的过程需要递归函数的返回值进行判断
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root == p || root == q || root == NULL) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left && right) return root;
if(left && !right) return left;
if(!left && right) return right;
return NULL; // !left && !right
}
};
leetcode 235 二叉搜索树的最近公共祖先
//如何利用二叉搜索树有序的特性
//只需要从上向下遍历的过程,cur节点数值在[p, q]区间中,则说明该节点cur就是最近公共祖先了。
//本题就是标准的搜索一条边的写法,遇到递归函数的返回值,如果不为空,立刻返回。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL) return root;
if(root->val <= max(p->val, q->val) && root->val >= min(p->val, q->val)) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
if(left) return left; //这里调用递归函数的地方,把递归函数的返回值left,直接return。
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(right) return right;
return NULL;
}
};
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 return root;
}
return root;
}
};
leetcode 701 二叉搜索树中的插入操作
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
recursive(root, val);
return root;
}
void recursive(TreeNode*& root, int val)
{
if(root == NULL)
{
root = new TreeNode(val);
return;
}
if(root->val > val) recursive(root->left, val);
else recursive(root->right, val);
}
};
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root == NULL)
{
root = new TreeNode(val);
return root;
}
if(root->val > val) root->left = insertIntoBST(root->left, val);
if(root->val < val) root->right = insertIntoBST(root->right, val);
return root;
}
};
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root == NULL)
{
root = new TreeNode(val);
return root;
}
TreeNode* parent = NULL;
TreeNode* cur = root;
while(cur)
{
parent = cur;
if(cur->val > val) cur = cur->left;
else cur = cur->right;
}
if(parent->val > val) parent->left = new TreeNode(val);
else parent->right = new TreeNode(val);
return root;
}
};
leetcode 450 删除二叉搜索树中的节点
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(root == NULL) return NULL; //1、没找到需要删除的元素
if(root->val == key)
{
if(!root->left && !root->right) //2、删除的元素是叶子节点
{
delete root;
return NULL;
}
if(!root->left) //3、删除节点左子树为空,删了该节点后,返回节点右子树,续上连接
{
TreeNode* tmp = root->right;
delete root;
return tmp;
}
if(!root->right) //4、同理
{
TreeNode* tmp = root->left;
delete root;
return tmp;
}
if(root->left && root->right) //5、删除节点左右子树都不为空,左子树连接到右子树最左下侧节点
{ //删除该节点后,返回该节点右子树,续上连接
TreeNode* rt = root->right;
while(rt->left)
{
rt = rt->left;
}
rt->left = root->left;
TreeNode* tmp = root->right;
delete root;
return tmp;
}
}
if(root->val > key) root->left = deleteNode(root->left, key);
if(root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
leetcode 669 修剪二叉搜索树
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if(root == NULL) return NULL;
if(root->val < low)
{
TreeNode* right = trimBST(root->right, low, high);
return right;
}
if(root->val > high)
{
TreeNode* left = trimBST(root->left, low, high);
return left;
}
if(root->left) root->left = trimBST(root->left, low, high);
if(root->right) root->right = trimBST(root->right, low, high);
return root;
}
};
// 错误写法,在修剪二叉树时候,当一个节点不符合条件时,不能只考虑该节点的删除,而且要考虑该节点的左右子树的情况
// TreeNode* trimBST(TreeNode* root, int low, int high) {
// if (root == nullptr || root->val < low || root->val > high) return nullptr;
// root->left = trimBST(root->left, low, high);
// root->right = trimBST(root->right, low, high);
// return root;
// }
迭代法
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if(root == NULL) return NULL;
// 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭
while(root != NULL && (root->val < low || root->val > high))
{
if(root->val < low)
{
root = root->right;
}
else //root->val > high
{
root = root->left;
}
}
TreeNode* cur = root;
// 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
while(cur != NULL)
{
while(cur->left && cur->left->val < low)
{
cur->left = cur->left->right;
}
cur = cur->left;
}
cur = root;
// 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
while(cur != NULL)
{
while(cur->right && cur->right->val > high)
{
cur->right = cur->right->left;
}
cur = cur->right;
}
return root;
}
};
leetcode 108 将有序数组转换为二叉搜索树
其实可以选择从start到end的任何一个值做为根结点,这里选择它们的中点,实际上,这样构建出来的是一颗平衡二叉搜索树。
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return recursive(nums, 0, nums.size()-1); //low high 左闭区间 右闭区间
}
TreeNode* recursive(vector<int>& nums, int low, int high)
{
if(low > high) return NULL;
int mid = low + (high - low) / 2; //当中间节点数量有两个时选择左边那个,该节点右子树比左子树多一个节点
//int mid = low + (high - low + 1) / 2; 当中间节点数量有两个时选择右边那个,该节点左子树比右子树多一个节点
TreeNode* root = new TreeNode(nums[mid]);
root->left = recursive(nums, low, mid-1);
root->right = recursive(nums, mid+1, high);
return root;
}
};
leetcode 95 不同的二叉搜索树 II
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
if(n) return recursiveFunc(1, n);
else return vector<TreeNode*>();
}
vector<TreeNode*> recursiveFunc(int left, int right)
{
vector<TreeNode*> result;
if(left > right)
{
result.push_back(NULL);
return result;
}
for(int i = left; i <= right; i++)
{
vector<TreeNode*> leftNodes = recursiveFunc(left, i-1);
vector<TreeNode*> rightNodes = recursiveFunc(i+1, right);
for(auto leftNode : leftNodes)
{
for(auto rightNode : rightNodes)
{
TreeNode* root = new TreeNode(i);
root->left = leftNode;
root->right = rightNode;
result.push_back(root);
}
}
}
return result;
}
};
leetcode 106 从中序与后序遍历序列构造二叉树
该题关键在于划分数组的边界条件的判断,特别在递归中进行处理,建议采用左闭右闭的方式,传入的直接就是数组可以访问的下标
//第一步:如果数组大小为零的话,说明是空节点了。
//第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
//第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
//第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
//第五步:切割后序数组,切成后序左数组和后序右数组
//第六步:递归处理左区间和右区间
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return recursiveFunc(inorder, 0, inorder.size()-1, postorder, 0, postorder.size()-1);
}
TreeNode* recursiveFunc(vector<int>& inorder, int ileft, int iright,
vector<int>& postorder, int pleft, int pright)
{
if(inorder.size() == 0 || postorder.size() == 0)
{
return NULL;
}
if(ileft > iright || pleft > pright)
{
return NULL;
}
int rootValue = postorder[pright];
TreeNode* root = new TreeNode(rootValue);
int ipovit;
for(int i = ileft; i <= iright; i++)
{
if(inorder[i] == rootValue)
{
ipovit = i;
}
}
int leftSum = ipovit - ileft;
root->left = recursiveFunc(inorder, ileft, ipovit - 1, postorder, pleft, pleft + leftSum - 1);
root->right = recursiveFunc(inorder, ipovit + 1, iright, postorder, pleft + leftSum, pright - 1);
return root;
}
};
leetcode 106 从前序与中序遍历序列构造二叉树
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return recursiveFunc(inorder, 0, inorder.size()-1, preorder, 0, preorder.size()-1);
}
TreeNode* recursiveFunc(vector<int>& inorder, int ileft, int iright,
vector<int>& preorder, int pleft, int pright)
{
if(inorder.size() == 0 || preorder.size() == 0)
{
return NULL;
}
if(ileft > iright || pleft > pright)
{
return NULL;
}
int rootValue = preorder[pleft];
TreeNode* root = new TreeNode(rootValue);
int ipovit;
for(int i = ileft; i <= iright; i++)
{
if(inorder[i] == rootValue)
{
ipovit = i;
}
}
int leftSum = ipovit - ileft;
root->left = recursiveFunc(inorder, ileft, ipovit - 1, preorder, pleft+1, pleft+leftSum);
root->right = recursiveFunc(inorder, ipovit + 1, iright, preorder, pleft+leftSum+1, pright);
return root;
}
};
leetcode 654 最大二叉树
一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。
构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return recursiveFunc(nums);
}
TreeNode* recursiveFunc(vector<int> nums)
{
if(nums.size() == 0) return NULL;
int max = INT_MIN;
int pivot;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] > max)
{
max = nums[i];
pivot = i;
}
}
TreeNode* root = new TreeNode(max);
vector<int> leftNums(nums.begin(), nums.begin()+pivot); // [0,pivot)
vector<int> rightNums(nums.begin()+pivot+1, nums.end()); // [pivot+1, end)
root->left = recursiveFunc(leftNums);
root->right = recursiveFunc(rightNums);
return root;
}
};
题目一:建立顺序存储结构存储的二叉树
TreeNode* creatBinaryTree(vector<int>& vec, int index)
{
if (index > vec.size() - 1) return NULL;
if (vec[index] == -1) return NULL;
TreeNode* root = new TreeNode(vec[index]);
root->left = creatBinaryTree(vec, 2 * index + 1);
root->right = creatBinaryTree(vec, 2 * index + 2);
return root;
}
题目二:判断顺序存储结构存储的二叉树是否为二叉搜索树
int preValue = INT_MIN;
void judgeBinarySearchTree(vector<int>& vec, int index, bool& flag)
{
if (index > vec.size() - 1) return;
if (vec[index] == -1) return;
if (flag == false) return;
judgeBinarySearchTree(vec, 2 * index + 1, flag);
if (vec[index] < preValue)
{
flag = false;
}
preValue = vec[index];
judgeBinarySearchTree(vec, 2 * index + 2, flag);
}
题目三:二叉树中查找值为x的结点,输出值为x的结点的所有祖先
//由二叉树非递归后序遍历的特点可以知道,当遍历到某个结点时,栈中的所有结点就是该结点的祖先,而从栈底到栈顶正是从根节点到该结点的路径。
void findnodeAncestor(TreeNode* root, int x) {
TreeNode* pre = NULL;
stack<TreeNode*> sck;
TreeNode* p = root;
while (p || !sck.empty()) {
if (p) {
sck.push(p);
p = p->lchild;
}
else {
p = sck.top();
if (p->rchild && p->rchild != pre) { //如果该结点的右子树存在,且右子树还未被访问过,则将遍历指针转向其右子树
p = p->rchild;
}
else {
p = sck.top();
sck.pop();
if (p->val == x) {
while (!sck.empty()) {
cout << sck.top()->val << endl;
sck.pop();
}
break;
}
pre = p;
p = NULL; //当后序遍历访问完一个结点时,代表已经访问完了以该结点为根的子树,需要将遍历指针p置空
}
}
}
}
void backtracking(vector<int>& result, vector<int> path, TreeNode* root, ElemType x) {
if (root == NULL) return;
if (root->val == x) {
path.push_back(x);
result = path;
return;
}
path.push_back(root->val);
backtracking(result, path, root->lchild, x);
backtracking(result, path, root->rchild, x);
path.pop_back();
}
题目四:二叉树中判断双分支结点的个数
int judgeBranchNum1(TreeNode* root) {
static int num = 0;
if (!root) return 0;
if (root->lchild && root->rchild) {
num++;
}
judgeBranchNum1(root->lchild);
judgeBranchNum1(root->rchild);
return num;
}
int judgeBranchNum2(TreeNode* root) {
if (!root) return 0;
if (root->lchild && root->rchild) {
return judgeBranchNum2(root->lchild) + judgeBranchNum2(root->rchild) + 1;
}
else {
return judgeBranchNum2(root->lchild) + judgeBranchNum2(root->rchild);
}
}
题目五:假设二叉树采用二叉链表存储设计,设计一个算法,求先序遍历序列中第k个结点的值。
1、首先需要记录目前递归访问的是第几个结点,可以采用设定一个全局变量或者静态局部变量来记录,如果采用函数传参的方式,对于这道题,不知道该怎么处理。
2、当访问到空结点时,返回特殊值65535,当找到我们需要的结点时,立即执行返回操作,不再进行遍历。
int findKthBinaryTree(TreeNode* root, int k) {
static int seqCount = 1;
if (root == NULL) {
return 65535;
}
if (seqCount == k) {
return root->val;
}
seqCount++;
int left = findKthBinaryTree(root->lchild, k);
if (left != 65535) {
return left;
}
else {
return findKthBinaryTree(root->rchild, k);
}
}
题目六:已知二叉树以二叉链表存储,编写算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间。
1、采用层序遍历搜索到该结点
2、然后用递归函数删除以该结点为根的子树
void deleteXTree(TreeNode* root) {
if (root == NULL) return;
deleteXTree(root->lchild);
deleteXTree(root->rchild);
delete root;
}
void searchDelete(TreeNode* root, int x) {
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
TreeNode* p = que.front();
que.pop();
if (p->lchild != NULL) {
if (p->lchild->val == x) {
deleteXTree(p->lchild);
p->lchild = NULL;
}
else {
que.push(p->lchild);
}
}
if (p->rchild != NULL) {
if (p->rchild->val == x) {
deleteXTree(p->rchild);
p->rchild = NULL;
}
else {
que.push(p->rchild);
}
}
}
return;
}