1 求二叉树的WPL
class Solution {
public:
int dfs(TreeNode *root, int depth) {
if (!root) return 0;
if (!root->left && !root->right) return root->val * depth;
return dfs(root->left, depth + 1) + dfs(root->right, depth + 1);
}
int pathSum(TreeNode *root) {
return dfs(root, 0);
}
};
2 重建二叉树
代码中 ( a , b ) 、 ( x , y ) (a,b)、(x,y) (a,b)、(x,y)分别代表先序遍历和中序遍历的左右边界
class Solution {
public:
unordered_map<int, int> pos;
vector<int> preorder, inorder;
TreeNode *build(int a, int b, int x, int y) {
if (a > b) return NULL;
auto root = new TreeNode(preorder[a]);
int k = pos[root->val];
root->left = build(a + 1, a + 1 + k - 1 - x, x, k - 1);
root->right = build(a + 1 + k - 1 - x + 1, b, k + 1, y);
return root;
}
TreeNode *buildTree(vector<int> &_preorder, vector<int> &_inorder) {
preorder = _preorder, inorder = _inorder;
int n = inorder.size();
for (int i = 0; i < n; i++) pos[inorder[i]] = i;
return build(0, n - 1, 0, n - 1);
}
};
3 最大的树
递归
class Solution {
public:
TreeNode *constructMaximumBinaryTree(vector<int> &nums) {
return build(nums, 0, nums.size() - 1);
}
TreeNode *build(const vector<int> &nums, int left, int right) {
if (left > right) return nullptr;
int top = left;
for (int i = left + 1; i <= right; i++)
if (nums[i] > nums[top]) top = i;
TreeNode *root = new TreeNode(nums[top]);
root->left = build(nums, left, top - 1);
root->right = build(nums, top + 1, right);
return root;
}
};
优化做法:
上面算法瓶颈在于找区间最大值,一般找区间最值有以下几种做法:
- 线段树:时间复杂度 O ( l o g n ) O(logn) O(logn),优点在于支持修改;
- S T ST ST表:时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn) (其中初始化 O ( n l o g n ) O(nlogn) O(nlogn),查找 O ( 1 ) O(1) O(1)),优点在于代码短。
这里使用 S T ST ST 表来处理, S T ST ST 里面记录的是最大值的下标。
class Solution {
public:
vector<vector<int>> f;
vector<int> nums;
int query(int l, int r) {
int k = log(r - l + 1) / log(2);
int a = f[l][k], b = f[r - (1 << k) + 1][k];
if (nums[a] > nums[b]) return a; else return b;
}
TreeNode *build(int l, int r) {
if (l > r) return nullptr;
int k = query(l, r);
TreeNode *root = new TreeNode(nums[k]);
root->left = build(l, k - 1), root->right = build(k + 1, r);
return root;
}
TreeNode *constructMaximumBinaryTree(vector<int> &_nums) {
nums = _nums;
int n = nums.size(), k = log(n) / log(2);
f = vector<vector<int >>(n, vector<int>(k + 1, 0));
for (int j = 0; j <= k; j++)
for (int i = 0; i + (1 << j) - 1 < n; i++)
if (!j) f[i][j] = i;
else {
int l = f[i][j - 1], r = f[i + (1 << (j - 1))][j - 1];
if (nums[l] > nums[r]) f[i][j] = l; else f[i][j] = r;
}
return build(0, n - 1);
}
};
4 二叉树排序
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 1e8;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int _val) : val(_val), left(nullptr), right(nullptr) {}
} *root;
void insert(TreeNode *&root, int x) {
if (!root) root = new TreeNode(x);
else if (x < root->val) insert(root->left, x);
else insert(root->right, x);
}
void remove(TreeNode *&root, int x) {
if (!root) return;
if (x < root->val) remove(root->left, x);
else if (x > root->val) remove(root->right, x);
else {
if (!root->left && !root->right) root = nullptr; // 为叶子节点
else if (!root->left) root = root->right; // 只有右子树
else if (!root->right) root = root->left; // 只有左子树
else {
auto p = root->left; // 找到左子树中右儿子中的最大值,用其值来代替,并删除其节点
while (p->right) p = p->right;
root->val = p->val;
remove(root->left, p->val);
}
}
}
int get_pre(TreeNode *root, int x) {
if (!root) return -INF;
if (root->val >= x) return get_pre(root->left, x);
return max(root->val, get_pre(root->right, x));
}
int get_suc(TreeNode *root, int x) {
if (!root) return INF;
if (root->val <= x) return get_suc(root->right, x);
return min(root->val, get_suc(root->left, x));
}
int main() {
int n; cin >> n;
while (n--) {
int t, x; cin >> t >> x;
if (t == 1) insert(root, x);
else if (t == 2) remove(root, x);
else if (t == 3) cout << get_pre(root, x) << endl;
else cout << get_suc(root, x) << endl;
}
return 0;
}
5 表达式树
求一棵表达式树的中缀表达式等价于对树做中序遍历,并在中序遍历的时候添加上括号。
O ( n 2 ) O(n^2) O(n2)写法
因为在C++中函数返回
string
类型的时候并不是将string
直接返回,而是将string
复制一遍。
class Solution {
public:
string dfs(TreeNode *root) {
if (!root) return "";
if (!root->left && !root->right) return root->val;
return '(' + dfs(root->left) + root->val + dfs(root->right) + ')';
}
string expressionTree(TreeNode *root) {
return dfs(root->left) + root->val + dfs(root->right); // 最外层是不需要添加括号的
}
};
O
(
n
)
O(n)
O(n)写法
每一次不是复制(返回),而是直接加上。
class Solution {
public:
string ans;
void dfs(TreeNode *root) {
if (!root) return;
if (!root->left && !root->right) ans += root->val;
else {
ans += '(';
dfs(root->left);
ans += root->val;
dfs(root->right);
ans += ')';
}
}
string expressionTree(TreeNode *root) {
dfs(root->left), ans += root->val, dfs(root->right);
return ans;
}
};
6 网络延时(树的直径)
求将每个点作为最高结点的时候,它到其所有儿子结点的最长距离和次长距离,该值就是以该节点为最高结点的最长路径。
时间复杂度: O ( n ) O(n) O(n)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010;
int n, m;
int h[N], e[N], ne[N], idx;
int ans;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dfs(int u) {
int d1 = 0, d2 = 0; // 当前结点下的最大长度和次大长度
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
int d = dfs(j);
if (d >= d1) d2 = d1, d1 = d;
else if (d > d2) d2 = d;
}
ans = max(ans, d1 + d2);
return d1 + 1; // +1 表示当前结点往父结点走的边
}
int main() {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for (int i = 2; i <= n + m; i++) {
int p; scanf("%d", &p);
add(p, i);
}
dfs(1);
printf("%d\n", ans);
return 0;
}
7 层数最深叶子节点的和
BFS:
class Solution {
public:
int deepestLeavesSum(TreeNode *root) {
int res = 0;
int hh = 0, tt = 0; TreeNode *q[10010]; q[0] = root;
while (hh <= tt) {
int s = tt - hh + 1; res = 0;
while (s--) {
auto t = q[hh++];
res += t->val;
if (t->left) q[++tt] = t->left;
if (t->right) q[++tt] = t->right;
}
}
return res;
}
};
DFS:
class Solution {
public:
int depth_max = -1, sum = 0;
void dfs(TreeNode *root, int depth) {
if (!root) return;
if (depth > depth_max) depth_max = depth, sum = root->val;
else if (depth == depth_max) sum += root->val;
dfs(root->left, depth + 1), dfs(root->right, depth + 1);
}
int deepestLeavesSum(TreeNode *root) {
dfs(root, 0);
return sum;
}
};
8 二叉树的高度
class Solution {
public:
int treeDepth(TreeNode* root) {
if (!root) return 0;
return max(treeDepth(root->left), treeDepth(root->right)) + 1;
}
};