迭代法实现深度优先遍历,以实现前序遍历,进而实现:
public void dfsPreOrder(TreeNode root){
Stack<TreeNode> treeNodes = new Stack<>();
TreeNode parent = null;
while(root != null || !treeNodes.isEmpty()){
while(root != null){
treeNodes.push(root);
if(root.left != null) {
map.put(root.left, root);
}
root = root.left;
}
root = treeNodes.pop();
if(root.right != null) {
map.put(root.right, root);
}
root = root.right;
}
}
递归法实现深度优先遍历,以实现前序遍历,进而实现:
public void dfs(TreeNode root) {
if(root.left != null) {
map.put(root.left, root);
dfs(root.left);
}
if(root.right != null) {
map.put(root.right, root);
dfs(root.right);
}
}
练习题:
法1:
迭代法实现深度优先遍历,以实现前序遍历:
class Solution {
Map<TreeNode, TreeNode> map = new HashMap<TreeNode, TreeNode>();
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
HashSet<Integer> hashSet = new HashSet<Integer>();
dfsPreOrder(root);
while (p!=null) {
hashSet.add(p.val);
p = map.get(p);
}
while (q!=null) {
if(hashSet.contains(q.val)) {
return q;
}
q = map.get(q);
}
return null;
}
public void dfsPreOrder(TreeNode root){
Stack<TreeNode> treeNodes = new Stack<>();
while(root != null || !treeNodes.isEmpty()){
while(root != null){
treeNodes.push(root);
if(root.left != null) {
map.put(root.left, root);
}
root = root.left;
}
root = treeNodes.pop();
if(root.right != null) {
map.put(root.right, root);
}
root = root.right;
}
}
}
执行用时:12 ms, 在所有 Java 提交中击败了8.24%的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了99.04%的用户
通过测试用例:31 / 31
递归法实现深度优先遍历,以实现前序遍历:
class Solution {
Map<TreeNode, TreeNode> map = new HashMap<TreeNode, TreeNode>();
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
HashSet<Integer> hashSet = new HashSet<Integer>();
dfs(root);
while (p!=null) {
hashSet.add(p.val);
p = map.get(p);
}
while (q!=null) {
if(hashSet.contains(q.val)) {
return q;
}
q = map.get(q);
}
return null;
}
public void dfs(TreeNode root) {
if(root.left != null) {
map.put(root.left, root);
dfs(root.left);
}
if(root.right != null) {
map.put(root.right, root);
dfs(root.right);
}
}
}
执行用时:11 ms, 在所有 Java 提交中击败了11.51%的用户
内存消耗:39.8 MB, 在所有 Java 提交中击败了97.22%的用户
通过测试用例:31 / 31
法2:递归法寻找最近公共祖先(LCA)
递归遍历整棵二叉树,定义f_x表示x结点的子树中是否包含p结点或者q结点,如果包含为true,如果不包含为false。
先给出符合条件的最近公共祖先结点x一定满足的条件:
(f_lson && f_rson)||((x == p)||(x == q)&&(f_lson || f_rson))
lson 和 rson 分别代表 x 节点的左孩子结点和右孩子结点。
f_lson && f_rson:表示p和q分别位于该两个结点最近结点x的左子树和右子树中。得到x是最近公共祖先。
((x == p)||(x == q)&&(f_lson || f_rson)):表示p或者q就是最近公共祖先。
其中f_lson 和 f_rson是要递归得到的,判断当前支树是否有p结点或者q结点。
递下去的时候,只有当 当前结点等于p或者q时才会返回true,之后归上去的时候把前面的boolean值携带着返回即可,并且能够保证只有p或者q在当前支树中。
class Solution {
private TreeNode ans;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root, p, q);
return ans;
}
public boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) {
return false;
}
boolean lson = dfs(root.left, p, q);
boolean rson = dfs(root.right, p, q);
if((lson && rson) || ((p.val == root.val || q.val == root.val) && (lson || rson))) {
ans = root;
}
return (p.val == root.val || q.val == root.val) || lson || rson;
}
}
执行用时:7 ms, 在所有 Java 提交中击败了57.42%的用户
内存消耗:40.5 MB, 在所有 Java 提交中击败了56.17%的用户
通过测试用例:31 / 31