面試準備系列03----面試中的二叉樹題目彙總

                                        面試準備系列03----面試中的二叉樹題目彙總

           本文是面試準備系列的第3篇,二叉樹和鏈表一樣,首先都應該想到遞歸。所以本文中儘量都用遞歸和非遞歸完成每一題。前一篇爲《面試準備系列03----面試中的二叉樹題目彙總》    

1.二叉樹的遍歷,前序中序後序,遞歸和非遞歸

http://blog.csdn.net/sheepmu/article/details/28941285

2.二叉樹的層序遍歷

3.二叉樹的高度/最小高度

4.二叉樹的節點個數

5.求二叉樹的鏡像

6.判斷兩顆二叉樹是否互爲鏡像

7.判斷一棵樹是否本身就是鏡像樹

8.判斷兩顆二叉樹是不是相同的樹

9.判斷樹1是不是樹2的子結構

10.判斷二叉樹是否是平衡二叉樹

11.二叉樹第k層的節點個數

12.二叉樹葉子節點的個數

13.由前序遍歷和中序遍歷重構二叉樹

14.由中序遍歷和後序遍歷重構二叉樹

15.二叉樹中兩節點的最大距離

16.二叉樹中和爲某一值的路徑

17.求二叉樹中兩個節點的最低公共祖先節點


package com.sheepmu;

import java.util.LinkedList;
import java.util.Stack;

class TreeNode
{
	String value;
	TreeNode left;
	TreeNode right;
	public TreeNode(String value ) 
	{
		this.value = value;
	}
	 
}
public class BinaryTree 
{
	//2.二叉樹的層序遍歷
	//思路:利用隊列實現二叉樹的層序遍歷。
	public  void cx(TreeNode root)
	{
		if(root==null)
			return;
		LinkedList<TreeNode> queue=new LinkedList<TreeNode>();
		queue.addLast(root);
		while(!queue.isEmpty())
		{
			TreeNode cur=queue.removeFirst();
			System.out.print(cur.value+" ");
			if(cur.left!=null) 
				queue.addLast(cur.left);			
			if(cur.right!=null)	 
				queue.addLast(cur.right);
			 	 
		}
	}
	
	//3.二叉樹的高度  --遞歸--
	public  int getHighRec(TreeNode root)
	{
		if(root==null)
			return 0;
		return Math.max(getHighRec(root.left), getHighRec(root.right))+1;
	}
	//3.二叉樹的高度  --非 遞歸--
	//思路:層序遍歷,對當前層和下一層的節點數計數。
	public  int getHigh(TreeNode root)
	{
		if(root==null)
			return 0;
		LinkedList<TreeNode> queue=new LinkedList<TreeNode>();
		queue.addLast(root);
		int high=0;
		int curLevelNodes=1,nextLevelNodes=0;
		while(!queue.isEmpty())
		{
			TreeNode cur=queue.removeFirst();
			curLevelNodes--;
			if(cur.left!=null)
			{
				queue.addLast(cur.left);
				nextLevelNodes++;
			}
			if(cur.right!=null)
			{
				queue.addLast(cur.right);
				nextLevelNodes++;
			}
			if(curLevelNodes==0)
			{
				high++;
				curLevelNodes=nextLevelNodes;
				nextLevelNodes=0;
			}	
		}
		return high;		 
	}
	
	//求二叉樹的最低高度,若有左or右子樹爲null的情況,則最小高度是另一非null子樹的最小高度 --遞歸--
	public int getMinHigh(TreeNode root)
	{
		if(root==null)
			return 0;
		if(root.left==null&&root.right==null)
			return 1;
		if(root.left==null)
			return 1+getMinHigh(root.right);
		if(root.right==null)
			return 1+getMinHigh(root.left);
		return 1+Math.min(getMinHigh(root.right),getMinHigh(root.left)) ;
	}
	//4.二叉樹的節點個數   --遞歸--
	public  int getNodesNumRec(TreeNode root)
	{
		if(root==null)
			return 0;
		return getNodesNumRec(root.left)+getNodesNumRec( root.right)+1;
	}
	//4.二叉樹的節點個數   --遞歸--
	//思路:層序遍歷記錄個數
	public  int getNodesNum(TreeNode root)
	{
		if(root==null)
			return 0;
		LinkedList<TreeNode> queue=new LinkedList<TreeNode>();
		queue.addLast(root);
		int num=1;
		while(!queue.isEmpty())
		{
			TreeNode cur=queue.removeFirst();
			if(cur.left!=null)
			{
				queue.addLast(cur.left);
				num++;
			}
			if(cur.right!=null)
			{
				queue.addLast(cur.right);
				num++;
			}
		}
		return num;
	}
	
	//5.求二叉樹的鏡像(直接把原樹變爲其鏡像樹,即破壞原樹)   --遞歸--
	//思路:把原樹的左子樹置爲其右子樹的鏡像;把原樹的右子樹置爲其左子樹的鏡像
	public  TreeNode getJXRec(TreeNode root)
	{
		if(root==null)
			return null;
		TreeNode tleft=getJXRec(root.right);
		TreeNode tright=getJXRec(root.left);
		root.left=tleft;
		root.right=tright;
		return root;
	}
	//5.求二叉樹的鏡像(直接把原樹變爲其鏡像樹,即破壞原樹)   --非遞歸--
	//思路: 利用Stsck,讓節點的子節點互相交換
	public  TreeNode getJX(TreeNode root)
	{
		if(root==null)
			return null;
		 Stack<TreeNode> stack=new Stack<TreeNode>();
		 stack.push(root);
		 while(!stack.isEmpty())
		 {
			 TreeNode cur=stack.pop();
			 TreeNode temp=cur.right;
			 cur.right=cur.left;
			 cur.left=temp;
			 if(cur.right!=null)
				 stack.push(cur.right);
			 if(cur.left!=null)
				 stack.push(cur.left);
		 }
		return root; 
	}
	//5.求二叉樹的鏡像(生成一顆新樹,即不改變原樹結構) --遞歸--
	public TreeNode newJXRec(TreeNode root)
	{
		if(root==null)
			return null;
		TreeNode newTree=new TreeNode (root.value);
		newTree.left=newJXRec(root.right);
		newTree.right=newJXRec(root.left);
		return newTree;
	}
	//5.求二叉樹的鏡像(生成一顆新樹,即不改變原樹結構) --非 遞歸--
	 
	//6.判斷兩個二叉樹是否互爲鏡像樹    --遞歸--
	public boolean isJXRec(TreeNode root1,TreeNode root2)
	{
		if(root1==null&&root2==null)
			return true;
		if(root1==null||root2==null)
			return false;
		if(root1.value!=root2.value)
			return false;
		return isJXRec( root1.left, root2.right)&&isJXRec( root1.right, root2.left);
	}
	//7.判斷一顆二叉樹本身是否爲鏡像樹    --遞歸--
		public boolean isJXRec2(TreeNode root)
		{
			 if(root==null)
				 return true;
			 return isJXRec2(root.left)&&isJXRec2(root.right);
				 
		}
	 //8.判斷兩顆二叉樹是不是相同的樹  --遞歸--
	public boolean isSameTreeRec(TreeNode root1,TreeNode root2)
	{
		if(root1==null&&root2==null)
			return true;
		if(root1==null||root2==null)
			return false;
		if(root1.value!=root2.value)
			return false;
		return isSameTreeRec( root1.left,root2.left)&&isSameTreeRec(root1.right,root2.right);
	}
	//8.判斷兩顆二叉樹是不是相同的樹  --非遞歸--
	public boolean isSameTree(TreeNode root1,TreeNode root2)
	{
		if(root1==null&&root2==null)
			return true;
		if(root1==null||root2==null)
			return false;
		if(root1.value!=root2.value)
			return false;
		Stack<TreeNode> stack1=new Stack<TreeNode>();
		Stack<TreeNode> stack2=new Stack<TreeNode>();
		stack1.push(root1);
		stack2.push(root2);
		while(!stack1.isEmpty()&&!stack1.isEmpty())
		{
			TreeNode cur1=stack1.pop();
			TreeNode cur2=stack2.pop();
			if(cur1.value!=cur2.value)
				return false;
			else 
			{
				if(cur1.right!=null&&cur2.right!=null)
				{
					stack1.push(cur1.right);
					stack2.push(cur2.right);
				}
				if(cur1.left!=null&&cur2.left!=null)
				{
					stack1.push(cur1.left);
					stack2.push(cur2.left);
				}
				if(cur1.left==null&&cur1.right==null&&cur2.left==null&&cur2.right==null)
					return true;
				else
					return false;
			}			
		}
		return true;
	}
	//9.判斷二叉樹1是不是二叉樹2的子結構
	
	
	
	//10.判斷二叉樹是否是平衡二叉樹    --遞歸--   但是這種方式雖然簡潔,但是每個節點會被遍歷多次,並不高效
	public boolean isBlanced(TreeNode root)
	{
		if(root==null)
			return true;
		if(Math.abs(getHighRec(root.left)-getHighRec(root.right))>1)//先判斷整個左右子樹高度差
			return false;
		return isBlanced(root.left)&&isBlanced( root.right);
	}
	//10.判斷二叉樹是否是平衡二叉樹    --遞歸--   更加高效的解法:每個節點只被遍歷一次
	//11.在遍歷的過程中一邊遍歷一邊計算高度
	public boolean isBlanced2(TreeNode root)
	{
		int high=0;
		return isBlanced3(root,high);
	}	
	public boolean  isBlanced3(TreeNode root,int high)
	{
		if(root==null)
		{
			high=0;
			return true;
		}
		int lefthigh=0,righthigh=0;
		if(isBlanced3(root.left,lefthigh)&&isBlanced3(root.right,righthigh))
		{
			if(Math.abs(lefthigh-righthigh)<=1)
			{
				high=1+Math.max(lefthigh, righthigh);
				return true;
			}
		}
		return false;
	}
	
	
	
	//11.求二叉樹第k層的節點個數  --遞歸--
	public int getNodesInKRec(TreeNode root,int k)
	{
		if(root==null||k<1)
			return 0;
		if( k==1)
			return 1;
		return  getNodesInKRec(root.left,k-1)+getNodesInKRec(root.right,k-1);
	}
	//11.求二叉樹第k層的節點個數  --非 遞歸--
	//思路:層序遍歷,類似於非遞歸求高度
	public int getNodesInK(TreeNode root,int k)
	{
		if(root==null||k<1)
			return 0;
		if(k==1)
			return 1;
		LinkedList<TreeNode> queue=new LinkedList<TreeNode>();
		queue.addLast(root);
		int curLevelNodes=1;
		int nextLevelNodes=0;
		int high=1;
		while(!queue.isEmpty()&&high<k)
		{
			TreeNode cur=queue.removeFirst();
			curLevelNodes--;
			if(cur.left!=null)
			{
				queue.addLast(root.left);
				nextLevelNodes++;
			}
			if(cur.right!=null)
			{
				queue.addLast(root.right);
				nextLevelNodes++;
			}
			if(curLevelNodes==0)	
			{
				high++;
				curLevelNodes=nextLevelNodes;
				nextLevelNodes=0;
			}
		}
		return curLevelNodes;
	}
	//12.求二叉樹的葉子節點數   --遞歸--
	public int getYeNodesRec(TreeNode root)
	{
		if(root==null)
			return 0;
		if(root.left==null&&root.right==null)
			return 1;
		return getYeNodesRec(root.left)+getYeNodesRec( root.right);
	}
	//12.求二叉樹的葉子節點數   --非遞歸--
	public int getYeNodes(TreeNode root)
	{
		if(root==null)
			return 0;
		if(root.left==null&&root.right==null)
			return 1;
		Stack<TreeNode> stack=new Stack<TreeNode>();
		stack.push(root);
		int num=0;
		while(!stack.isEmpty())
		{
			TreeNode cur=stack.pop();
			if(cur.right!=null)
			{
				stack.push(cur.right);
			}
			if(cur.left!=null)
			{
				stack.push(cur.left);
			}
			if(cur.right==null&&cur.left==null)
				num++;
		}
		return num;
	}
	//13.由前序遍歷和中序遍歷重構二叉樹  --遞歸--
	//先找到根節點,在分別找到左右子樹的前序和中序,遞歸
	public TreeNode buildTreeRec(String pre,String mid)
	{
		if(pre==null||mid==null)
			return null;
		if(pre.length()==0||mid.length()==0)
			return null;
		if(pre.length()!=mid.length())
			return null;
		int len=pre.length();
		TreeNode root=new TreeNode(pre.charAt(0)+"");//先找到根節點,前序遍歷的第一個是根節點
		int i=0;
		while(mid.charAt(i)!=pre.charAt(0))//找到中序遍歷中根節點的位置,那麼它前面的即是左樹,後面的是右樹 
			i++;
		 
		root.left=	buildTreeRec(pre.substring(1, 1+i) ,mid.substring(0, i) );//由左樹的前序和後序構造新左樹
		root.right=	buildTreeRec(pre.substring(i+1, len) ,mid.substring(i+1, len) );//由右樹的前序和後序構造新的右樹
		return root;	
	}
	//14.由中序遍歷和後序遍歷重構二叉樹 --遞歸--
	//先找到根節點,在分別找到左右子樹的中序和後序,遞歸
	public TreeNode buildTreeRec2(String mid,String pro)
	{
		if(mid==null||pro==null)
			return null;
		if(mid.length()==0||pro.length()==0)
			return null;
		if(mid.length()!=pro.length())
			return null;
		int len=mid.length();
		TreeNode root=new TreeNode(pro.charAt(len-1)+"");//後序的最後一個是根節點
		int i=0;
		while(mid.charAt(i)!=pro.charAt(len-1))//找到中序遍歷中根節點的位置,那麼它前面的即是左樹,後面的是右樹
			i++;
		root.left=buildTreeRec2( mid.substring(0, i),pro.substring(0, i) );
		root.right=buildTreeRec2( mid.substring(i+1, len),pro.substring(i, len-1) );
		return root;
	}
	//15.二叉樹中兩節點的最大距離
	/**
	 * 計算一個二叉樹的最大距離有兩個情況: 
		 
	        情況A: 路徑經過左子樹的最深節點,通過根節點,再到右子樹的最深節點。 
	        情況B: 路徑不穿過根節點,而是左子樹或右子樹的最大距離路徑,取其大者。 
	        只需要計算這兩個情況的路徑距離,並取其大者,就是該二叉樹的最大距離 
 
	 */
	    public static Result getMaxDistanceRec(TreeNode root)
	    {  
	        if(root == null)
	        {  
	            Result empty = new Result(0, -1);       // 目的是讓調用方 +1 後,把當前的不存在的 (NULL) 子樹當成最大深度爲 0  
	            return empty;  
	        }  
	          
	        // 計算出左右子樹分別最大距離  
	        Result lmd = getMaxDistanceRec(root.left);  
	        Result rmd = getMaxDistanceRec(root.right);  
	          
	        Result res = new Result();  
	        res.maxDepth = Math.max(lmd.maxDepth, rmd.maxDepth) + 1;        // 當前最大深度  
	        // 取情況A和情況B中較大值  
	        res.maxDistance = Math.max( lmd.maxDepth+rmd.maxDepth, Math.max(lmd.maxDistance, rmd.maxDistance) );  
	        return res;  
	    }  
	      
	    private static class Result
	    {  
	        int maxDistance;  
	        int maxDepth;  
	        public Result() 
	        {  
	        }  	  
	        public Result(int maxDistance, int maxDepth)
	        {  
	            this.maxDistance = maxDistance;  
	            this.maxDepth = maxDepth;  
	        }  
	    }  
	
	
	
	
	//16.最低公共祖先節點
	public TreeNode getLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2) 
	{  
        if(root == null)   
            return null;             
        // 如果有一個match,則說明當前node就是要找的最低公共祖先  注意遞歸條件!!!!!
        if(root.equals(n1) || root.equals(n2))  
            return root;    
        TreeNode commonInLeft = getLastCommonParentRec(root.left, n1, n2);  
        TreeNode commonInRight = getLastCommonParentRec(root.right, n1, n2);   
        // 如果一個左子樹找到,一個在右子樹找到,則說明root是唯一可能的最低公共祖先  
        if(commonInLeft!=null && commonInRight!=null)   
            return root;  
        // 其他情況是要不然在左子樹要不然在右子樹  
        if(commonInLeft != null)  
            return commonInLeft;   
        return commonInRight;  
    }  
	
	
	/* 
                                 A  
                               /   \  
                             B      C  
                            / \        \  
                          D    E        F  
                                
                               
  */  
	public static void main(String[] args)
	{
		TreeNode n1=new TreeNode("A");
		TreeNode n2=new TreeNode("B");
		TreeNode n3=new TreeNode("C");
		TreeNode n4=new TreeNode("D");
		TreeNode n5=new TreeNode("E");
		TreeNode n6=new TreeNode("F");
		n1.left=n2;
		n1.right=n3;
		n2.left=n4;
		n2.right=n5;
		n3.right=n6;
		TreeNode root=n1;
		BinaryTree bt=new BinaryTree();
		System.out.print("層序遍歷---->" );
		bt.cx(root);
		System.out.print("\n");
		System.out.println("遞歸高度---->"+bt.getHighRec(root));
		System.out.println("非遞歸高度---->"+bt.getHigh(root));
		System.out.println("遞歸節點個數---->"+bt.getNodesNumRec(root));
		System.out.println("非遞歸節點個數---->"+bt.getNodesNum(root));
		 
//		 bt.getJXRec(root);
//		 bt.cx(root);
//		 System.out.print("\n");
//		System.out.print("把樹變爲本身的鏡像樹後層序遍歷---->" );
//		 bt.getJX(root);
//		 bt.cx(root);
		System.out.println("是否是平衡二叉樹---->"+bt.isBlanced(root));
		System.out.println("是否是平衡二叉樹,每個節點只遍歷一次的方法---->"+bt.isBlanced2(root));
		System.out.println("遞歸第 k層節點個數---->"+bt.getNodesInKRec(root, 3));
		System.out.println("非遞歸第 k層節點個數---->"+bt.getNodesInK(root, 3));
		System.out.println("遞歸葉節點個數---->"+bt.getYeNodesRec(root));
		System.out.println("非遞歸葉節點個數---->"+bt.getYeNodes(root));
		System.out.print("由前序遍歷和中序遍歷構造的樹的  層序遍歷---->" );
		bt.cx(bt.buildTreeRec("ABDECF", "DBEACF"));
		System.out.print("\n" );
		System.out.print("由中序遍歷和後序遍歷構造的樹的  層序遍歷---->" );
		bt.cx(bt.buildTreeRec2("DBEACF", "DEBFCA"));
		System.out.print("\n" );
		System.out.println("最低公共祖先---->"+bt.getLastCommonParentRec(root,n4,n3).value);
	}
}
層序遍歷---->A B C D E F 
遞歸高度---->3
非遞歸高度---->3
遞歸節點個數---->6
非遞歸節點個數---->6
是否是平衡二叉樹---->true
是否是平衡二叉樹,每個節點只遍歷一次的方法---->true
遞歸第 k層節點個數---->3
非遞歸第 k層節點個數---->3
遞歸葉節點個數---->3
非遞歸葉節點個數---->3
由前序遍歷和中序遍歷構造的樹的  層序遍歷---->A B C D E F 
由中序遍歷和後序遍歷構造的樹的  層序遍歷---->A B C D E F 
最低公共祖先---->A

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章