路径与路径和
Given a binary tree, return all root-to-leaf paths.
For example, given the following binary tree:
1 / 2 3 5 All root-to-leaf paths are:
["1->2->5", "1->3"]
用 StringBuilder 传递可以省去递归中新建的 string copies.
StringBuilder 的回溯也很简单,直接 setLength(int len) 就行。
在 leaf node 上以 sb.setLength() 收尾是为了 backtracking,因为后面的两个 dfs 都没有做,不走到底是不会回溯的,要由到了 leaf node 那一层递归进行处理。这点和常见的 subsets 和 permutations 不太一样,那两题中收尾直接 add 然后 return 就可以了,而回溯在 dfs 之后做。
在 dfs 之后直接 backtracking 会遇到问题,例如路径上某个分叉上只有一边有节点,向 null 方向探索之后会删掉来路。
public class Solution {
public void help(List<String> list, TreeNode node, StringBuilder sb) {
if (node == null) return;
// 存盘,保存当前路径
int len=sb.length();
sb.append(node.val);
if (node.left == null && node.right == null) {
list.add(sb.toString());
// 抹掉末尾数字
sb.setLength(len);
return;
}
sb.append("->");
help(list, node.left, sb);
help(list, node.right, sb);
// 抹掉箭头和前一个数字
sb.setLength(len);
}
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<String>();
help(res, root, new StringBuilder());
return res;
}
}和前一题研究的 Tree DFS + Backtracking 完全一个套路。只不过回溯的时候,记得把 curSum 也给回溯了就行。
5/27 号重做了一遍,这次的代码
简化版,这次不用存所有的 Paths 了,套用 Tree DFS 模板可以,不过在只求 boolean / int 的情况下,也有更简单直接的写法。
或者更直接点,
这题有点 Tricky,不好做。假定有如下的Tree:
最大和路径有这么几种可能:
从 root 出发,路上看到负数,不采用;
从 root 出发,路上看到负数,负数后面存在总和超过负数节点的路径;
最大和在某个从 leaf node 往上走的一条路径上,不过 root.
左路径最大,采用左路径;
右路径最大,采用右路径;
单独节点最大,可能是 左/右/根 其中之一。
换句话说,一个重要的问题是,我们只能从 root 开始,也没有 parent 指针,但是最优的路径可能却和 root 是不连续的,这就切断了 Binary Tree divide & conquer / Tree DFS 里面大多数做法中非常依赖的性质,即层层递归之前 左/右 子树和根节点的联系。
然而套路还是要用的,要么这题就没法做了。。好在问题没有要求返回具体 path ,只要一个 max sum, 想连接全局最优就要用一个全局变量 int max. 从 leaf node 开始 bottom-up 进行处理的时候还不需要考虑“切断”的问题,因此还可以用套路,注意随时更新全局 max 就好。从 bottom-up 的角度看,这是一个从底部不停 merge 最优的子路径在根节点会和的过程。
每一层的“三角形”路径都要和全局最优 update 一下,然而不是有效的 path. 最终 return 的结果只是“必须包括当前节点” 的最大 path,由此完成连续的递归结构(recurrence substructure)
另外一个小技巧是,在求 max sum 的情况下,每一个节点可以有 “选”(root.val) 或者 “不选” (0) 两种选择,在单个
如果不喜欢这种用全局变量的方式,也可以用如下九章的解法,其实骨子里面的思路一样,把全局变量用一个 tuple 包起来了。
比较值得参考的是这种 dfs 之间传 tuple 的方式很好的解决了信息传递的问题,其中的变量可以是符合递归连续结构的,也可以是全局的,看起来比较适合 generalize 到其他 Tree 的问题。
都是套路啊,套路。Top-Bottom 的递归回溯。
如果 dfs 里面共享的变量是 String 或者 primitive type ,那么不存在多层递归共同 reference 的问题,backtracking 的步骤也就可以省去了。
从这个角度看,其实很多看起来非常简洁的 Binary Tree 问题都是因为 dfs 函数里面没有 by reference 的东西,属于 dfs + backtracking 的低配简化版。
全局最优解不一定和 root 与 dfs 递归连续,因而用全局变量 int max 解决。 其他部分无压力套模板。
不爱用全局变量也好办,建个长度为 1 的 int[] 当参数传就行了。
Last updated
Was this helpful?