The Largest Independent Set (LIS) of a binary tree is defined as the largest subset of nodes in the tree such that no two nodes in the subset have an edge connecting them. In other words, the LIS is the largest set of nodes that can be selected from the tree in such a way that no two selected nodes are adjacent.
The dynamic programming approach to solve this problem involves recursively computing the LIS of each subtree of the binary tree, and then combining these results to obtain the LIS of the entire tree.
We can define a function LIS(node) which returns the size of the LIS of the subtree rooted at the given node. The function can be defined recursively as follows:
- If the given node is a leaf, the LIS is 1.
- If the given node is not selected, we can compute the LIS of its children and return the sum of these values.
- If the given node is selected, we cannot select any of its children. Instead, we must compute the LIS of its grandchildren (the children of its children) and return the sum of these values plus one.
By using memoization (storing intermediate results), we can avoid recomputing the LIS of each subtree multiple times. The memoization table can be implemented using a HashMap, with the tree nodes as keys and the LIS values as values.
Here’s a Java implementation of this approach:
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class LISBinaryTree {
Map<TreeNode, Integer> memo = new HashMap<>();
public int largestIndependentSet(TreeNode root) {
if (root == null) return 0;
if (memo.containsKey(root)) return memo.get(root);
int size = 0;
// compute LIS excluding root
size += largestIndependentSet(root.left);
size += largestIndependentSet(root.right);
// compute LIS including root
if (root.left != null) {
size += largestIndependentSet(root.left.left);
size += largestIndependentSet(root.left.right);
}
if (root.right != null) {
size += largestIndependentSet(root.right.left);
size += largestIndependentSet(root.right.right);
}
int lis = Math.max(size + 1, largestIndependentSet(root.left) + largestIndependentSet(root.right));
memo.put(root, lis);
return lis;
}
}
We start by initializing a memoization table using a HashMap. The ‘largestIndependentSet‘ function takes a binary tree node as input, and recursively computes the LIS of the subtree rooted at that node using the memoization table to avoid recomputing values.
The size of the subtree LIS is computed by recursively calling ‘largestIndependentSet‘ on the left and right child nodes, adding their return values, and adding the size of the LIS of the grandchildren of the root, if any. If the root is included in the LIS, we return the sum of the sizes of the grandchildren plus one. Otherwise, we return the maximum LIS excluding the root and the LIS including the root.
Finally, we look up the LIS of the root in the memoization table. If it is present, we return it. Otherwise, we add it to the memoization table and return it.