标题: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 + " ");
}
}
}
}