本篇blog主要使用递归方式解决Tree的DFS问题,至于非递归方式,需要使用堆栈的方式。具体的原理可以参考《算法导论》。
对于Tree的深度搜索问题的解题模式:
1)首先判断是否能够用深度搜索策略(DFS)解决问题。DFS能够解决的问题的一般特点是:如果把左右子树作为独立的Tree来看,使用同样的算法同样可以解决;
2)确认DFS可以解决问题后,一般使用递归的方式解决问题。确定递归的退出条件和处理是关键,也就是边界的处理:(1)叶结点是边界(2)Tree的倒数第二层是边界,等等;
3)运用递归的方式处理左子树和右子树;
4)root,左子树和右子树都处理后,集中三者的处理结果得出问题的最终解;
描述:Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node
int maxDepth(struct TreeNode* root) {
int depth = 0;
int leftDepth;
int rightDepth;
//如果空树,深度为0
if(root == NULL)
{
return depth;
}
// 递归求解左儿子和右儿子的深度
leftDepth = maxDepth(root->left);
rightDepth = maxDepth(root->right);
// 在左儿子和右儿子之间选取较大的深度加上1就是整个树的深度
if(leftDepth > rightDepth)
{
depth = leftDepth + 1;
}
else
{
depth = rightDepth + 1;
}
return depth;
}
描述:Invert a binary tree.
4
/ \
2 7
/ \ / \
1 3 6 9
to
4
/ \
7 2
/ \ / \
9 6 3 1
struct TreeNode* invertTree(struct TreeNode* root)
{
struct TreeNode *p;
//树空则返回
if(root == NULL)
{
return root;
}
// 交换root的左儿子和右儿子
p = root->left;
root->left = root->right;
root->right = p;
// 递归invert root的左儿子
invertTree(root->left);
// 递归invert root的右儿子
invertTree(root->right);
return root;
}
描述:Given two binary trees, write a function to check if they are equal or not.Two binary trees are considered equal if they are structurally identical and the nodes have the same value
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
bool a = false;
bool b = false;
bool c = false;
// 两树都空,则相同
if(p == NULL && q == NULL)
{
return true;
}
//任意一棵树空,另一颗不空,则不同
if(p == NULL && q != NULL)
{
return false;
}
if(p != NULL && q == NULL)
{
return false;
}
//value不同则不同
if(p->val != q->val)
{
return false;
}
a = true;
// 递归check p和q的左儿子是否相同
b = isSameTree(p->left,q->left);
// 递归check p和q的右儿子是否相同
c = isSameTree(p->right,q->right);
// 只有p和q相同,对应的左儿子和右儿子都相同,两树才相同
if(a == true && b == true && c == true)
{
return true;
}else
{
return false;
}
}
描述:Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
bool isBalanced(struct TreeNode* root) {
int leftHeight;
int rightHeight;
int ret = 0;
bool a = false,b = false,c = false;
// 空树是balanced
if(root == NULL)
{
return true;
}
// 计算左子树和右子树的深度
leftHeight = maxDepth(root->left);
rightHeight = maxDepth(root->right);
// 如果左子树和右子树的深度差小于1,则root是balanced
if(abs(leftHeight - rightHeight) < 2)
{
c = true;
}
// 判断左子树和右子树是否balanced
a = isBalanced(root->left);
b = isBalanced(root->right);
// 如果root,左子树,右子树都是balanced,则该树是balanced
if(a == true && b == true && c == true)
{
return true;
}else
{
return false;
}
}
描述:Given a binary tree, find its minimum depth.The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node
int minDepth(struct TreeNode* root)
{
int depth = 0;
int depthLeft = 0;
int depthRight = 0;
// 空树深度为0
if(root == NULL)
{
return depth;
}
//递归计算左子树和右子树的深度
depthLeft = minDepth(root->left);
depthRight = minDepth(root->right);
if(root->left == NULL) //左子树空时,深度为右子树深度加1
{
depth = depthRight + 1;
}else if(root->right == NULL)//右子树空时,深度为左子树深度加1
{
depth = depthLeft + 1;
}
else //左子树和右子树都非空时,深度为较浅的子树深度加1
{
if(depthLeft > depthRight)
{
depth = depthRight + 1;
}else
{
depth = depthLeft + 1;
}
}
return depth;
}
描述:Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum
bool hasPathSum(struct TreeNode* root, int sum)
{
int rootVal = 0;
bool a = false;
bool b = false;
// 空树返回false
if(root == NULL)
{
return false;
}
// 如果到达叶结点了,并且sum和叶结点的值相等了,说明有这样的路径,否则没有这样的路径
rootVal = root->val;
if(root->left == NULL && root->right == NULL)
{
if(rootVal == sum)
{
return true;
}
else
{
return false;
}
}else //如果不是叶结点,那么sum的值减去root的值,同时递归check左子树和右子树
{
a = hasPathSum(root->left,sum - rootVal);
b = hasPathSum(root->right,sum - rootVal);
}
if(a == true || b == true)
{
return true;
}else
{
return false;
}
}
描述:Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.
bool isValidBST(struct TreeNode* root)
{
bool a = false,b = false;
struct TreeNode* p1;
// 空树总是Valid
if(root == NULL)
{
return true;
}
// 左子树最大值比根小才valid
if(root->left != NULL)
{
p1 = root->left;
while(p1 != NULL)
{
if(p1->val >= root->val)
{
return false;
}
p1 = p1->right;
}
}
// 右子树最小值比根大才valid
if(root->right != NULL)
{
p1 = root->right;
while(p1 != NULL)
{
if(p1->val <= root->val)
{
return false;
}
p1 = p1->left;
}
}
// 递归判断左子树和右子树
a = isValidBST(root->left);
b = isValidBST(root->right);
// 左右子树都valid 才valid
if(a == true && b == true)
{
return true;
}else
{
return false;
}
}
描述:Given a binary tree, return the preorder traversal of its nodes’ values.
For example:
Given binary tree {1,#,2,3},
1
\
2
/
3
int calculateTreeSize(struct TreeNode *root)
{
int size = 0;
if(root == NULL)
{
return 0;
}
size += calculateTreeSize(root->left);
size += calculateTreeSize(root->right);
size++;
return size;
}
int* saveTreeElement(struct TreeNode *root, int *p)
{
if(root == NULL)
{
return p;
}
(*p) = root->val;
if(root->left != NULL)
{
p++;
p = saveTreeElement(root->left,p);
}
if(root->right != NULL)
{
p++;
p = saveTreeElement(root->right,p);
}
return p;
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
int size = 0;
int *p;
if(root == NULL)
{
return NULL;
}
// Calculate the total size
size = calculateTreeSize(root);
*returnSize = size;
p = malloc(size * sizeof(int));
saveTreeElement(root,p);
return p;
}
描述:Given a binary tree, return the inorder traversal of its nodes’ values.
For example:
Given binary tree {1,#,2,3},
1
\
2
/
3
return [1,3,2].
int countNode(struct TreeNode *root)
{
int size = 0;
if(root == NULL)
{
return size;
}
size += countNode(root->left);
size += countNode(root->right);
size++;
return size;
}
int* saveTreeElement(struct TreeNode *root, int *p)
{
if(root == NULL)
{
return p;
}
if(root->left != NULL)
{
p = saveTreeElement(root->left,p);
p++;
}
(*p) = root->val;
if(root->right != NULL)
{
p++;
p = saveTreeElement(root->right,p);
}
return p;
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int size = 0;
int *p;
if(root == NULL)
{
return NULL;
}
// Calculate the total size
size = countNode(root);
*returnSize = size;
p = malloc(size * sizeof(int));
saveTreeElement(root,p);
return p;
}
描述:Given a binary tree, return the postorder traversal of its nodes’ values.
For example:
Given binary tree {1,#,2,3},
1
\
2
/
3
return [3,2,1].
int calculateTreeSize(struct TreeNode *root)
{
int size = 0;
if(root == NULL)
{
return 0;
}
size += calculateTreeSize(root->left);
size += calculateTreeSize(root->right);
size++;
return size;
}
int* saveTreeElement(struct TreeNode *root, int *p)
{
if(root == NULL)
{
return p;
}
if(root->left != NULL)
{
p = saveTreeElement(root->left,p);
p++;
}
if(root->right != NULL)
{
p = saveTreeElement(root->right,p);
p++;
}
(*p) = root->val;
return p;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
int size = 0;
int *p;
if(root == NULL)
{
return NULL;
}
// Calculate the total size
size = calculateTreeSize(root);
*returnSize = size;
p = malloc(size * sizeof(int));
saveTreeElement(root,p);
return p;
}
描述:Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
For example, this binary tree is symmetric:
1
/ \
2 2
/ \ / \
3 4 4 3
But the following is not:
1
/ \
2 2
\ \
3 3
bool dfs(struct TreeNode* left,struct TreeNode* right)
{
bool a = false,b = false;
// 如果左子树的结点和右子树的结点都空,则是对称的
if(left == NULL && right == NULL)
{
return true;
}
// 一侧为空或者值不等则不对称
if(left == NULL || right == NULL || left->val != right->val)
{
return false;
}
// 递归检测left->left 与 right->right是否对称
a = dfs(left->left,right->right);
// 递归检测left->right 与 right->left是否对称
b = dfs(left->right,right->left);
// 只有都对称才是对称的
return (a && b);
}
bool isSymmetric(struct TreeNode* root)
{
// 空树或者只有一个节点是对称的
if(root == NULL)
{
return true;
}
return dfs(root->left,root->right);
}
描述:Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
1
/ \
2 3
Return 6.
int maxSum(struct TreeNode* root, int* max)
{
int value;
int lmax = 0,rmax = 0;
// 空树路径长度为0
if(root == NULL)
{
return 0;
}
// 以root为根的当前tree,递归计算左子树和右子树的最大路径
value = root->val;
lmax = maxSum(root->left,max);
rmax = maxSum(root->right,max);
// 如果左子树最大路径大于0,则根节点加上左子树最大路径长
if(lmax > 0)
{
value += lmax;
}
// 如果右子树最大路径大于0,则根节点加上右子树最大路径长
if(rmax > 0)
{
value += rmax;
}
// 比较当前root为根的树的最大路径与max值,如果大于max值,则更新max
if(value > *max)
{
*max = value;
}
/* 1)如果左子树和右子树最大路径都小于0,则返回根的值
2)如果lmax或者rmax至少一个为正,那么返回较大的路径
*/
if(lmax > 0 || rmax > 0)
{
if(lmax > rmax)
{
return (root->val + lmax);
}else
{
return (root->val + rmax);
}
}
else
{
return root->val;
}
}
int maxPathSum(struct TreeNode* root)
{
//max用来记录遍历过的路径中最大值
int max = INT_MIN;
maxSum(root,&max);
return max;
}
描述:Given a binary tree, flatten it to a linked list in-place.
For example,
Given
1
/ \
2 5
/ \ \
3 4 6
The flattened tree should look like:
1
\
2
\
3
\
4
\
5
\
6
void flatten(struct TreeNode* root)
{
struct TreeNode* p1,*p2;
if(root == NULL)
{
return;
}
flatten(root->left);
flatten(root->right);
if(root->left == NULL)
{
return; //左子树为空时说明已经完成
}else if(root->right == NULL) //右子树空时直接将左子树挪到右子树即可
{
root->right = root->left;
root->left = NULL;
}else
{
/*
此时默认左子树已经完成,那么首先找到左子树的最右最深的结点,右子树将挂载在这个叶结点上
*/
p1 = root->left;
while(p1->right != NULL)
{
p1 = p1->right;
}
p2 = root->right;
root->right = root->left;
p1->right = p2;
root->left = NULL;
}
return;
}
https://leetcode.com/problemset/algorithms/