使用哈希表存储二叉树所有结点的父结点的实现方式

这篇博客介绍了两种方法实现二叉树的深度优先遍历,包括迭代法和递归法,以进行前序遍历。接着,利用这些遍历方法解决了一个实际问题——找到二叉树中两个节点的最近公共祖先(LCA)。迭代法和递归法的执行时间和内存消耗进行了对比,并给出了具体代码实现。
摘要由CSDN通过智能技术生成

迭代法实现深度优先遍历,以实现前序遍历,进而实现:

    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值