二叉树两个节点的最低公共最先问题

2022-11-30 16:58:23 浏览数 (1)

代码语言:javascript复制
package com.test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;

/**
 * 回溯法寻找路径问题
 * @author zhangteng
 *
 */
public class Main {

	static class Node{
		int data;
		Node left;
		Node right;
	    public Node(int data){
	    	this.data=data;
	    }
	}
	
	static class PathNode{
		Node pNode;
		boolean left=false;
		boolean right=false;
		char direct;
		public PathNode(Node pNode){
			this.pNode=pNode;
		}
	}
	private static Stack<PathNode> findPath(Node tree,Node purpose){
		Stack<PathNode> s=new Stack<PathNode>();
		
		Node now=tree;
		if(now==purpose){
			return null;
		}//初始化工作
		PathNode temp=new PathNode(now);
		temp.direct='l';
		if(now.left==null){
			temp.left=true;
			temp.direct='r';
		}
		if(now.right==null){
			if(temp.direct=='r'){
				temp.direct='e';
			}
			temp.right=true;
		}
		s.push(temp);
		while(s.peek().pNode!=purpose&&!s.isEmpty()){
		   if(s.peek().direct=='e'){
			   return s;
		   }
		   //System.out.println(s.peek().pNode.data);
		   if(!s.peek().left){
			  if(s.peek().pNode.left!=null){
				  now=s.peek().pNode.left;
				  s.peek().left=true;
				  s.peek().direct='l';
				  temp=new PathNode(now);
				  s.push(temp);
			  }else{
				  s.peek().left=true;
			  }
		   }else if(!s.peek().right){
			   if(s.peek().pNode.right!=null){
				   now=s.peek().pNode.right;
				   s.peek().right=true;
				   s.peek().direct='r';
				   temp=new PathNode(now);
				   s.push(temp);
			   }else{
				   s.peek().right=true;
			   }
		   }else if(s.peek().left&&s.peek().right){
			   s.pop();
		   }
		}
		//s.pop();
		return s;
	}
	
	public static List<Character> getPath(Node root,Node purpose){
		List<Character> list=new ArrayList<Character>();
		Stack<PathNode> st=findPath(root, purpose);
		if(st==null){
			//节点就是根节点所以没路径
			return list;
		}else if(st.size()==0){
			//没找到路径
			return null;
		}else{
			Stack<PathNode> temp=new Stack<PathNode>();
			while(!st.isEmpty()){
			   temp.push(st.pop());
			}
			while(!temp.isEmpty()){
				list.add(temp.pop().direct);
			}
			return list;
		}
	}
	
	public static Node getGradFather(Node root,Node p1,Node p2){
		//找到节点p1的路径
		List<Character> path1=getPath(root, p1);
		//找到节点p2的路径
		List<Character> path2=getPath(root, p2);
		if(path1==null||path2==null){
			//路径1或者路径2为空也就是没找到
			return null;
		}else if(path1.size()==0||path2.size()==0){
			//没有路径就代表是根节点所以最低最先一定是根节点
			return root;
		}else{
			List<Character> sharePath=new ArrayList<Character>();
			for(int i=0;path1.get(i)==path2.get(i);i  ){
				sharePath.add(path1.get(i));
			}
			Node temp=root;
			for(int j=0;j<sharePath.size();j  ){
				if(sharePath.get(j)=='l'){
					temp=temp.left;
				}else{
					temp=temp.right;
				}
			}
			return temp;
		}
	}
	public static void main(String[] args) {
		Node t1=new Node(1);
		Node t2=new Node(2);
		Node t3=new Node(3);
		Node t4=new Node(4);
		Node t5=new Node(5);
		Node t6=new Node(6);
		Node t7=new Node(7);
        t1.left=t2;
        t1.right=t3;
        t2.left=t4;
        t2.right=t5;
        t3.left=t6;
        t3.right=t7;
        
        System.out.print(getGradFather(t1, t1, t3).data);
	}

}

今天我遇到一个问题,问题描述如下:

        寻找二叉树,两个节点的最低公共祖先,最低公共祖先意思是从下往上两个节点遇到的第一个祖先。

解决这个问题的思路有两种:

1.从根节点往下寻找,如果发现两个节点分别在左右子树上那么就找到了最低公共祖先,这是一个思路,但是这种算法实现起来复杂度比较高,所以放弃,选择第二种思路

2.第二种思路是,两个节点,分别找到,从根节点到这两个节点的路径,找到路径后问题就转变为求两个链表的交叉点,这样就好做多了,就是从根节点按照路径往下遍历,如果果首次发现两个链表的节点不是同一个节点了,那么两个链表上一个公共节点就是最低祖先,首先得问题就是怎么找到路径,我解决这个问题的方法是回溯法,新建一个类,这个类的成员变量有二叉树的节点,两个布尔型变量,代表左右子树是否被遍历过,false为没有遍历,true为已经遍历过了,还有一个变量就存放着走向,‘l’代表向左走,‘r’代表向右走,从根节点开始如果左子树没遍历过,就把左孩子压入栈,如果有右子树没有遍历,就把右孩子压入栈,下一轮循环中再以栈顶元素为当前节点查看条件,如果说左右子树都被遍历,那么就回溯,让栈顶元素出栈,如果找到元素,那么就返回,如果栈为空了,那么就证明没有找到,想要的节点。以下是我代码:

0 人点赞