Java,实现得到二叉树的最近公共祖先节点

24 篇文章 0 订阅
23 篇文章 0 订阅

标题:Java,实现得到二叉树的最近公共祖先节点

一、方法四种:

在这里插入图片描述具体代码见下面:

首先做这个题目,感觉知道这个会比较好:
//供参考的后序迭代输出二叉树的所有节点

//供参考的后序迭代输出二叉树的所有节点
public void postOrder(TreeNode head){
	if(head == null){
		return ;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);

	while(!s.isEmpty()){
		TreeNode p = s.peek();
		if(p.left != null){
			s.push(p.left);
		}else{
			//System.out.print(p.val + " ");
			while(p.right == null){
				TreeNode last = s.pop();
				System.out.print(last.val + " ");
				
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					System.out.print(last.val + " ");
				}
				
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
				//System.out.print(p.val + " ");
			}			
		}		
	}
}

1)方法一:递归
执行用时:7 ms, 在所有 Java 提交中击败了99.85% 的用户
内存消耗:40.5 MB, 在所有 Java 提交中击败了82.40% 的用户

/*
方法一:递归
执行用时:7 ms, 在所有 Java 提交中击败了99.85% 的用户
内存消耗:40.5 MB, 在所有 Java 提交中击败了82.40% 的用户
*/
public TreeNode getCommonNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null){
		return null;
	}else{
		if(head.val == p1.val || head.val == p2.val){  //如果条件满足,return 此节点
			return head;
		}
		TreeNode n1 = this.getCommonNode(head.left, p1, p2);
		TreeNode n2 = this.getCommonNode(head.right, p1, p2);
		if(n1 != null && n2 != null){   //此外的条件,都需要遍历完 左右的节点才知道
			return head;
		}
			
		return n1 == null? n2 : n1;
	}
}

2)方法二:得到两个list
执行用时:16 ms, 在所有 Java 提交中击败了6.76% 的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了99.58% 的用户

/*
方法二:得到两个list
执行用时:16 ms, 在所有 Java 提交中击败了6.76% 的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了99.58% 的用户
*/
public TreeNode prePostOrderTocommonTreeNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null || p1 == null || p2 == null){
		return null;
	}
	List<TreeNode> list1 = this.prePostOrderToList(head, p1);
	List<TreeNode> list2 = this.prePostOrderToList(head, p2);

	TreeNode node = null;
	for(int i = list1.size() - 1, j = list2.size() - 1; i >= 0 && j >= 0; i--, j--){
		if(list1.get(i) == list2.get(j)){ //若两个值一样,则继续遍历,保存元素,若不一样,则说明node为公共祖先节点
			node = list1.get(i);
		}else{
			break;
		}
	}

	return node;
}

/*
先序遍历[后序的思想],得到list
*/
public List<TreeNode> prePostOrderToList(TreeNode head, TreeNode pNode){
	List<TreeNode> list = new ArrayList<>();
	if(head == null || pNode == null){
		return list;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);

	while(!s.isEmpty()){
		TreeNode p = s.peek();
		System.out.print(p.val + " ");
		if(pNode.val == p.val){
			break;
		}
		if(p.left != null){
			s.push(p.left);
		}else{
			while(p.right == null){
				TreeNode last = s.pop();
				//System.out.print(last.val + " ");
				
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					//System.out.print(last.val + " ");
				}
				
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
			}	
			if(s.isEmpty()){
				break;
			}else {
				s.push(p.right);
			}			
		}		
	}
	Iterator<TreeNode> it = s.iterator();
	while(it.hasNext()){
		list.add(it.next());
	}
	
	return list;
}

3)方法三:迭代 【先序的后序写法】 1122之前的写法
思想:通过先序遍历,先找到一个满足条件的node,
继续遍历:
若不需要需要退栈,找到了再次满足条件的,return node,
若需要退栈,pop出 node,则取node = s.peek();

执行用时:9 ms, 在所有 Java 提交中击败了29.26% 的用户
内存消耗:39.5 MB, 在所有 Java 提交中击败了98.93% 的用户

/*
方法三:迭代 【先序的后序写法】  1122之前的写法
思想:通过先序遍历,先找到一个满足条件的node,
继续遍历:
若不需要需要退栈,找到了再次满足条件的,return node,
若需要退栈,pop出 node,则取node = s.peek();

执行用时:9 ms, 在所有 Java 提交中击败了29.26% 的用户
内存消耗:39.5 MB, 在所有 Java 提交中击败了98.93% 的用户
*/
public TreeNode prePostOrderTocommonNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null || p1 == null || p2 == null){
		return null;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);
	int count = 0;
	TreeNode node = null;
	
	while(!s.isEmpty()){
		TreeNode p = s.peek();
		System.out.print(p.val + " ");
		//判断是否满足条件
		if(p.val == p1.val || p.val == p2.val){
			count++;
			if(count == 1){
				node = p;
			}else {
				return node;
			}
		}
		
		if(p.left != null){
			s.push(p.left);
		}else{
			while(p.right == null){
				TreeNode last = s.pop();
				//System.out.print(last.val + " ");
				//重新为node赋值
				if(node != null && node.val == last.val){
					node = null;
				}
				
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					//System.out.print(last.val + " ");
					//重新为node赋值
					if(node != null && node.val == last.val){
						node = null;
					}
				}
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
				//为node赋值
				if(node == null){
					node = p;
				}
			}
			if(s.isEmpty()){
				break;
			}else {
				s.push(p.right);
			}
						
		}		
	}
	return null;
}

4)方法四:迭代 【中序的后序写法】 1122写法 【很明显不需要这样通过中序遍历解题,直接通过上述的先序遍历即可】
思想:通过中序遍历,先找到一个满足条件的node,
继续遍历:
若不需要需要退栈,找到了再次满足条件的,return node,
若需要退栈,pop出 node,则取node = s.peek();

执行用时:10 ms, 在所有 Java 提交中击败了23.24% 的用户
内存消耗:38.9 MB, 在所有 Java 提交中击败了99.76% 的用户

/*
方法四:迭代 【中序的后序写法】  1122写法  【很明显不需要这样通过中序遍历解题,直接通过上述的先序遍历即可】
思想:通过中序遍历,先找到一个满足条件的node,
继续遍历:
若不需要需要退栈,找到了再次满足条件的,return node,
若需要退栈,pop出 node,则取node = s.peek();

执行用时:10 ms, 在所有 Java 提交中击败了23.24% 的用户
内存消耗:38.9 MB, 在所有 Java 提交中击败了99.76% 的用户
*/
public TreeNode inPostOrderToCommonNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null || p1 == null || p2 == null){
		return null;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);
	int count = 0;
	TreeNode node = null;
	
	while(!s.isEmpty()){
		TreeNode p = s.peek();
		if(p.left != null){
			s.push(p.left);
		}else{
			System.out.print(p.val + " ");
			//判断是否找到
			if(p.val == p1.val || p.val == p2.val){
				count++;
				if(count == 1){
					node = p;
				}else{
					return node;
				}
			}
			
			while(p.right == null){
				TreeNode last = s.pop();
				//System.out.print(last.val + " ");
				//将node-》null
				if(node != null && last.val == node.val){
					node = null;
				}
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					//System.out.print(last.val + " ");
					//将node-》null
					if(node != null && last.val == node.val){
						node = null;
					}
				}
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
				System.out.print(p.val + " ");
				if(node == null){
					node = p;
				}
				//判断是否找到
				if(p.val == p1.val || p.val == p2.val){
					count++;
					if(count == 1){
						node = p;
					}else{
						return node;
					}
				}
			}	
			
			if(s.isEmpty()){
				break;
			}else {
				s.push(p.right);
			}			
		}		
	}
	
	return null;
}

完整示例代码:

/*
方法一:递归
执行用时:7 ms, 在所有 Java 提交中击败了99.85% 的用户
内存消耗:40.5 MB, 在所有 Java 提交中击败了82.40% 的用户
*/
public TreeNode getCommonNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null){
		return null;
	}else{
		if(head.val == p1.val || head.val == p2.val){  //如果条件满足,return 此节点
			return head;
		}
		TreeNode n1 = this.getCommonNode(head.left, p1, p2);
		TreeNode n2 = this.getCommonNode(head.right, p1, p2);
		if(n1 != null && n2 != null){   //此外的条件,都需要遍历完 左右的节点才知道
			return head;
		}
			
		return n1 == null? n2 : n1;
	}
}

/*
方法二:得到两个list
执行用时:16 ms, 在所有 Java 提交中击败了6.76% 的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了99.58% 的用户
*/
public TreeNode prePostOrderTocommonTreeNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null || p1 == null || p2 == null){
		return null;
	}
	List<TreeNode> list1 = this.prePostOrderToList(head, p1);
	List<TreeNode> list2 = this.prePostOrderToList(head, p2);

	TreeNode node = null;
	for(int i = list1.size() - 1, j = list2.size() - 1; i >= 0 && j >= 0; i--, j--){
		if(list1.get(i) == list2.get(j)){ //若两个值一样,则继续遍历,保存元素,若不一样,则说明node为公共祖先节点
			node = list1.get(i);
		}else{
			break;
		}
	}

	return node;
}

/*
先序遍历,得到list
*/
public List<TreeNode> prePostOrderToList(TreeNode head, TreeNode pNode){
	List<TreeNode> list = new ArrayList<>();
	if(head == null || pNode == null){
		return list;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);

	while(!s.isEmpty()){
		TreeNode p = s.peek();
		System.out.print(p.val + " ");
		if(pNode.val == p.val){
			break;
		}
		if(p.left != null){
			s.push(p.left);
		}else{
			while(p.right == null){
				TreeNode last = s.pop();
				//System.out.print(last.val + " ");
				
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					//System.out.print(last.val + " ");
				}
				
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
			}	
			if(s.isEmpty()){
				break;
			}else {
				s.push(p.right);
			}			
		}		
	}
	Iterator<TreeNode> it = s.iterator();
	while(it.hasNext()){
		list.add(it.next());
	}
	
	return list;
}


/*
方法三:迭代 【先序的后序写法】  1122之前的写法
思想:通过先序遍历,先找到一个满足条件的node,
继续遍历:
若不需要需要退栈,找到了再次满足条件的,return node,
若需要退栈,pop出 node,则取node = s.peek();

执行用时:9 ms, 在所有 Java 提交中击败了29.26% 的用户
内存消耗:39.5 MB, 在所有 Java 提交中击败了98.93% 的用户
*/
public TreeNode prePostOrderTocommonNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null || p1 == null || p2 == null){
		return null;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);
	int count = 0;
	TreeNode node = null;
	
	while(!s.isEmpty()){
		TreeNode p = s.peek();
		System.out.print(p.val + " ");
		//判断是否满足条件
		if(p.val == p1.val || p.val == p2.val){
			count++;
			if(count == 1){
				node = p;
			}else {
				return node;
			}
		}
		
		if(p.left != null){
			s.push(p.left);
		}else{
			while(p.right == null){
				TreeNode last = s.pop();
				//System.out.print(last.val + " ");
				//重新为node赋值
				if(node != null && node.val == last.val){
					node = null;
				}
				
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					//System.out.print(last.val + " ");
					//重新为node赋值
					if(node != null && node.val == last.val){
						node = null;
					}
				}
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
				//为node赋值
				if(node == null){
					node = p;
				}
			}
			if(s.isEmpty()){
				break;
			}else {
				s.push(p.right);
			}
						
		}		
	}
	return null;
}

/*
方法四:迭代 【中序的后序写法】  1122写法  【很明显不需要这样通过中序遍历解题,直接通过上述的先序遍历即可】
思想:通过中序遍历,先找到一个满足条件的node,
继续遍历:
若不需要需要退栈,找到了再次满足条件的,return node,
若需要退栈,pop出 node,则取node = s.peek();

执行用时:10 ms, 在所有 Java 提交中击败了23.24% 的用户
内存消耗:38.9 MB, 在所有 Java 提交中击败了99.76% 的用户
*/
public TreeNode inPostOrderToCommonNode(TreeNode head, TreeNode p1, TreeNode p2){
	if(head == null || p1 == null || p2 == null){
		return null;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);
	int count = 0;
	TreeNode node = null;
	
	while(!s.isEmpty()){
		TreeNode p = s.peek();
		if(p.left != null){
			s.push(p.left);
		}else{
			System.out.print(p.val + " ");
			//判断是否找到
			if(p.val == p1.val || p.val == p2.val){
				count++;
				if(count == 1){
					node = p;
				}else{
					return node;
				}
			}
			
			while(p.right == null){
				TreeNode last = s.pop();
				//System.out.print(last.val + " ");
				//将node-》null
				if(node != null && last.val == node.val){
					node = null;
				}
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					//System.out.print(last.val + " ");
					//将node-》null
					if(node != null && last.val == node.val){
						node = null;
					}
				}
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
				System.out.print(p.val + " ");
				if(node == null){
					node = p;
				}
				//判断是否找到
				if(p.val == p1.val || p.val == p2.val){
					count++;
					if(count == 1){
						node = p;
					}else{
						return node;
					}
				}
			}	
			
			if(s.isEmpty()){
				break;
			}else {
				s.push(p.right);
			}			
		}		
	}
	
	return null;
}





//供参考的后序迭代输出二叉树的所有节点
public void postOrder(TreeNode head){
	if(head == null){
		return ;
	}
	Deque<TreeNode> s = new LinkedList<>();
	s.push(head);

	while(!s.isEmpty()){
		TreeNode p = s.peek();
		if(p.left != null){
			s.push(p.left);
		}else{
			//System.out.print(p.val + " ");
			while(p.right == null){
				TreeNode last = s.pop();
				System.out.print(last.val + " ");
				
				while(!s.isEmpty() && s.peek().right == last){
					last = s.pop();
					System.out.print(last.val + " ");
				}
				
				if(s.isEmpty()){
					break;
				}
				p = s.peek();
				//System.out.print(p.val + " ");
			}			
		}		
	}
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java二叉树最近公共祖先可以通过递归来解决。首先,我们需要定义一个TreeNode类表示二叉树节点,其中包含值和左右子节点的引用。下面是一个示例代码: ```java class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int val) { this.val = val; } } ``` 接下来,我们可以实现一个递归函数来找到最近公共祖先: ```java public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // 判断当前节点是否为空或者等于p或q if (root == null || root == p || root == q) { return root; } // 在左子树中寻找最近公共祖先 TreeNode left = lowestCommonAncestor(root.left, p, q); // 在右子树中寻找最近公共祖先 TreeNode right = lowestCommonAncestor(root.right, p, q); // 如果左子树和右子树都找到了最近公共祖先,则当前节点就是最近公共祖先 if (left != null && right != null) { return root; } // 如果只有左子树找到了最近公共祖先,则返回左子树的结果 if (left != null) { return left; } // 如果只有右子树找到了最近公共祖先,则返回右子树的结果 if (right != null) { return right; } // 如果左右子树都没有找到最近公共祖先,则返回null return null; } ``` 这个递归函数的基本思路是: - 当前节点为空或者等于p或q时,直接返回当前节点; - 在左子树中寻找最近公共祖先; - 在右子树中寻找最近公共祖先; - 如果左子树和右子树都找到了最近公共祖先,则当前节点就是最近公共祖先; - 如果只有左子树找到了最近公共祖先,则返回左子树的结果; - 如果只有右子树找到了最近公共祖先,则返回右子树的结果; - 如果左右子树都没有找到最近公共祖先,则返回null。 你可以调用这个函数来找到二叉树中任意两个节点最近公共祖先

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值