Paths in Tree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private int sum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
dfs(root);
return sum;
}
/**
* Max sum of paths which start from node.
* @param node the root of the subtree
* @return the max sum of paths starting from node
*/
private int dfs(TreeNode node) {
if (node == null) {
return 0;
}
int left = Math.max(0, dfs(node.left)), right = Math.max(0, dfs(node.right));
sum = Math.max(sum, node.val + left + right);
return node.val + Math.max(left, right);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private int path = 0;
public int longestUnivaluePath(TreeNode root) {
length(root);
return path;
}
/**
* Max length of univalue paths which start from node.
* @param node the root of the subtree
* @return the max length of univalue paths starting from node
*/
private int length(TreeNode node) {
if (node == null) {
return 0;
}
// max univalue paths from the child nodes
int left = length(node.left), right = length(node.right);
// max univalue paths from the current node
int leftPath = 0, rightPath = 0;
if (node.left != null && node.left.val == node.val) {
leftPath = left + 1;
}
if (node.right != null && node.right.val == node.val) {
rightPath = right + 1;
}
path = Math.max(path, leftPath + rightPath);
return Math.max(leftPath, rightPath);
}
Longest ZigZag Path in a Binary Tree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public int longestZigZag(TreeNode root) {
return dfs(root)[2];
}
private int[] dfs(TreeNode node) {
if (node == null) {
// max zigzag path at:
// [0]: left child node
// [1]: right child node
// [2]: this node
return new int[]{-1, -1, -1};
}
int[] left = dfs(node.left), right = dfs(node.right);
// left[1], right[0] makes the path zigzag
// leaves will have zigzag path == -1 + 1 == 0
int path = Math.max(Math.max(left[1], right[0]) + 1, Math.max(left[2], right[2]));
return new int[]{left[1] + 1, right[0] + 1, path};
}
Leaf-to-leaf Paths
Aggregate paths from current node to all leaf nodes in its subtree.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int diameter = 0;
int getHeight(TreeNode* node) {
if (node == nullptr) {
return 0;
}
int left = getHeight(node->left), right = getHeight(node->right);
diameter = max(diameter, left + right);
return max(left, right) + 1;
}
public:
int diameterOfBinaryTree(TreeNode* root) {
getHeight(root);
return diameter;
}
Similar problem: Diameter of N-Ary Tree
Number of Good Leaf Nodes Pairs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private int distance = 0;
private int pairs = 0;
public int countPairs(TreeNode root, int distance) {
this.distance = distance;
dfs(root);
return pairs;
}
// arr[i]: the number of leaf nodes whose distances to the current node is (i - 1)
private int[] dfs(TreeNode node) {
int[] count = new int[distance + 1];
if (node == null) {
return count;
}
if (node.left == node.right) {
count[1] = 1;
return count;
}
int[] left = dfs(node.left), right = dfs(node.right);
// Prefix sum of right
int[] p = new int[right.length];
for (int i = 0; i < distance; i++) {
p[i + 1] = p[i] + right[i];
}
for (int i = 1; i < distance; i++) {
// p[distance - i + 1] = sum(right[0]...right[distance - 1])
// i.e. count of all right nodes where left[i] + right[j] <= distance
pairs += left[i] * p[distance - i + 1];
}
for (int i = 1; i < distance; i++) {
count[i + 1] = left[i] + right[i];
}
return count;
}
Any-to-any Paths
Aggregate paths from current node to all ancestor nodes in its subtree.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
vector<bool> notPrime;
long long cnt = 0;
// Number of paths from `node` to its ancestors:
// p[i]: paths contain i prime numbers
pair<int,int> dfs(const vector<vector<int>>& g, int node, int parent) {
// 0 if not prime; 1 otherwise.
pair<int,int> p = {notPrime[node], !notPrime[node]};
for (int neighbor : g[node]) {
if (neighbor != parent) {
auto np = dfs(g, neighbor, node);
// cnt and p are updated in every iteration - this trick is very important
// If cnt is updated after the for loop, there can be invalid paths
// e.g. 3-4-1-2, uses 1 as root
// When 1 is the current node, 1-3 and 1-4 would be viewed as valid segments
// which composes the path. But that is not valid, since 3 and 4 are from the same subtree.
cnt += (long long)np.first * p.second + (long long)np.second * p.first;
if (notPrime[node]) {
p.first += np.first;
p.second += np.second;
} else {
p.second += np.first;
}
}
}
return p;
}
public:
long long countPaths(int n, vector<vector<int>>& edges) {
vector<vector<int>> g(n + 1, vector<int>{});
for (const auto& e : edges) {
g[e[0]].push_back(e[1]);
g[e[1]].push_back(e[0]);
}
notPrime.resize(n + 1);
notPrime[1] = true;
for (int i = 2; i <= n; i++) {
if (!notPrime[i]) {
for (int j = i; (long long)i * j <= n; j++) {
notPrime[i * j] = true;
}
}
}
dfs(g, 1, 0);
return cnt;
}
This post is licensed under CC BY 4.0 by the author.