一般而言,大多数动态规划dp是基于数组结构的,其实,在树状结构中也能实现dp,下面就两道算法题给出例子
1:二叉树最长路径
题目描述:https://leetcode.com/problems/sum-of-subarray-minimums/
思路:二叉树最长路径来源于以下三者之中的最大——左子树、右子树、左子树深度+右子树深度
容易写出以下递归的解法:
public static int diameterOfBinaryTree(TreeNode root) {
if (root == null) return 0;
if(root.left == null && root.right == null) return 1;
int a = depth(root.left) + depth(root.right), b = diameterOfBinaryTree(root.left), c = diameterOfBinaryTree(root.right);
return Math.max(a,
Math.max(b, c)
);
}
private static int depth(TreeNode root) {
if (root == null) return 0;
return 1 + Math.max(depth(root.left), depth(root.right));
}
提交上去后,发现只击败了10%的java提交,不难发现,这里递归的子问题是:每棵子树的深度和最长路径, 对于这些子问题,我们进行了重复计算。现在可以思考:如何对于一个子问题,只进行一次计算?
对于每棵子树,他的深度与内部最长路径可以看作是一个属性,用一个int数组(内含两个属性:深度与内部最长路径)来存储,并不断向上(自己的根节点)返回
基于这个思路,我们写出了下面的代码
// 树型dp
public static int diameterOfBinaryTree1(TreeNode root) {
return process(root)[0];
}
// int[2] = [best, height]
private static int[] process(TreeNode node) {
if (node == null) return new int[]{0, 0};
int[] left = process(node.left);
int[] right = process(node.right);
int[] info = new int[2];
int maxOfLeftAndRight = Math.max(left[0], right[0]);
info[0] = Math.max(maxOfLeftAndRight, left[1] + right[1]);
info[1] = 1 + Math.max(left[1], right[1]);
return info;
}
击败了100%的java提交