昨天又被关于树的题目给虐了。。树结构决定了递归是其一个非常重要的方法。今天重新回顾下树结构,并用题目练手。
先从树中的最长路径开始:
解题的关键在于我们要认识到最长的路径一定是某个节点下的两个最长分支的长度和。这里我们并不一定知道是哪个节点,所以可以使用 set 将每个节点的下的最长路径存储起来,最后返回最大的那个。
对于是当前节点的那个两个分支,我们可以使用 vector 存储所有分支长度,然后用 sort 排序后给出。
题目的实现可以用后序遍历的方法以时间复杂度O(N)完成。利用后序遍历算出当前节点下各分支长度。需要小心的是对于长度的定义各题有所不同,有的题是路径上的所有点个数,有的则是经过枝干的个数(即所有点个数 - 1)。
#1050 : 树中的最长路
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
#define MAXN 100010
set<int> myMax;
set<int>::reverse_iterator iter;
struct Node
{
int id;
int next;
}node[MAXN * 2];
void Init(int N)
{
int i = 1, ai, bi;
for(; i <= N; ++i)
node[i].id = i;
for(; i <= 2 * N - 1; ++i)
{
scanf("%d %d", &ai, &bi);
node[i].id = bi;
node[i].next = node[ai].next;
node[ai].next = i;
}
}
int myfindMax(int root)
{
int num = 0, numChild, i;
set<int> nodeMax;
while(node[root].next)
{
root = node[root].next;
numChild = myfindMax(node[root].id);
nodeMax.insert(numChild);
}
for(i = 0, iter = nodeMax.rbegin(); i < 2; ++i, ++iter)
{
if(iter == nodeMax.rend())
break;
num += *iter;
}
myMax.insert(num);
iter = nodeMax.rbegin();
if(nodeMax.empty())
return 1;
else
return 1 + *iter;
}
int findMax(int root)
{
myfindMax(root);
iter = myMax.rbegin();
return *iter;
}
int main()
{
int N;
scanf("%d", &N);
if(!N)
{
printf("%d\n", 0);
return 0;
}
Init(N);
printf("%d\n", findMax(1));
return 0;
}
leetcode #104. Maximum Depth of Binary Tree
//DFS即可,注意树的深度定义也不尽相同,有的将root深度定义为0,有的为1
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int Depth = 0;
void DFS(TreeNode *root)
{
if(root -> val > Depth)
Depth = root -> val;
if(root -> left)
{
root -> left -> val = root -> val + 1;
DFS(root -> left);
}
if(root -> right)
{
root -> right -> val = root -> val + 1;
DFS(root -> right);
}
}
int maxDepth(TreeNode* root) {
if(root == NULL)
return 0;
root -> val = 1;
DFS(root);
return Depth;
}
};
然后是树的中序遍历 leetcode #94. Binary Tree Inorder Traversal
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorder;
void myinorder(TreeNode *root)
{
if(root -> left)
myinorder(root -> left);
inorder.push_back(root -> val);
if(root -> right)
myinorder(root -> right);
}
vector<int> inorderTraversal(TreeNode* root) {
if(root == NULL)
return inorder;
myinorder(root);
return inorder;
}
};
BST不同结构的数量,leetcode #96. Unique Binary Search Trees
这道题开始的思路错了,把问题给想的复杂了,其实就是一道比较简单的dp题目。关键在于要认识到一颗BST由根,左子树和右子树组成。对于一颗由 n 个节点组成的 BST,左子树与右子树分享剩下的 n - 1 个节点。如果用 num[n] 表示 n 个节点 BST 的数量,那么有这样的递归关系:
num[n] = sigma(num[i] * num[n - i - 1]) i表示左子树的节点树, n - i - 1为右子树的节点树。i : 0 ~ n - 1
注意我们定义 num[0] = num[1] = 1
有了这个递推关系,代码就水到渠成:
class Solution {
public:
int num[1000000];
int numTrees(int n) {
num[0] = num[1] = 1;
int i, j;
if(n == 0)
return 0;
if(n == 1)
return 1;
for(i = 2; i <= n; ++i)
for(j = 0; j < i; ++j)
num[i] += num[j] * num[i - j - 1];
return num[n];
}
};
然后是这道题的加强版,要求输出其所有的 BST,leetcode #95. Unique Binary Search Trees II
受到上面那道题的启发,这道题也可以采用类似的方法。着手点从于根节点开始,拼接两颗之前已经得到的树作为当前根节点的左右子树(对于 N 节点的树,其树上节点值为 1 ~ N)。当前树是 BST ,所以根节点值是左子树最大值加一,右子树是将每个节点的值加上根节点的值,就能得到一颗新的 BST(也即我们正好可以利用之前得到的树)。拼接的过程需要一个树的 copy() 函数。此外我们使用二维vector来存储树根。
代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<TreeNode *> > ans;
vector<TreeNode *> zero;
//拷贝一棵树,并将每个节点的值加val
TreeNode* copy(TreeNode *root, int val)
{
if(root == NULL) return NULL;
TreeNode *p = new TreeNode(root -> val + val);
p -> left = copy(root -> left, val);
p -> right = copy(root -> right, val);
return p;
}
vector<TreeNode*> generateTrees(int n) {
if(n == 0)
return zero;
ans.push_back(vector<TreeNode *>());
ans[0].push_back(NULL);
int i, j, l, r;
//递推n
for(i = 1; i <= n; ++i)
{
ans.push_back(vector<TreeNode *>());
//根节点取值
for(j = 1; j <= i; ++j)
{
for(l = 0; l < ans[j - 1].size(); ++l)
{
for(r = 0; r < ans[i - j].size(); ++r)
{
TreeNode *p = new TreeNode(j);
p -> left = copy(ans[j - 1][l], 0);
p -> right = copy(ans[i - j][r], j);
ans[i].push_back(p);
}
}
}
}
return ans[n];
}
};