1. 程式人生 > 其它 >java面試演算法筆記- 07 二叉樹的遞迴

java面試演算法筆記- 07 二叉樹的遞迴

技術標籤:java資料結構演算法

07 二叉樹的遞迴

可以解決面試中絕大多數的二叉樹問題尤其是樹型dp問題

本質是利用遞迴遍歷二叉樹的便利性

二叉樹的遞迴套路

1)假設以X節點為頭,假設可以向X左樹和X右樹要任何資訊
2)在上一步的假設下,討論以X為頭節點的樹,得到答案的可能性(最重要) 常見分類: 與x無關,與x有關

3)列出所有可能性後,確定到底需要向左樹和右樹要什麼樣的資訊
4)把左樹資訊和右樹資訊求全集,就是任何一棵子樹都需要返回的資訊S
5)遞迴函式都返回S,每一棵子樹都這麼要求
6)寫程式碼,在程式碼中考慮如何把左樹的資訊和右樹資訊整合出整棵樹的資訊

​ 難點:

​ 1、假設分類

​ 2、具體的可能性,需要什麼具體資訊

​ 3、如何實現遞迴函式

​ 1、base case
2、遞迴左右樹
​ 3、加工該次如何返回要求資訊

題目

1、isBalance

​ 給定一棵二叉樹的頭節點head,返回這顆二叉樹是不是平衡二叉樹

​ 1、列舉全部可能

​ 1、) 左樹

​ 樹高

​ 是否為平衡二叉樹

​ 2、)右樹

​ 樹高

​ 是否為平衡二叉樹

​ 2、需要資訊就是樹高,和是否為平衡二叉樹(畫遞迴樹)

	Info process(Node head){
        //base case
    if(x == null){
        return 0; //樹高為0
    }
//遞迴 Info(x.left); Info(x.right); //處理該次的資訊返回 height = max(左樹高,右樹高) + 1; if(左樹.isAK && 右樹.isAK && abs(左樹.height - 右樹.height)<=1){ Info(x).isAk = true; } }

2、is滿二叉樹

​ 給出一個head,返回這顆樹是否是滿二叉樹

​ method1、暴力解法

​ 1、找到樹高height

​ 2、遍歷樹節點個數nodes

​ 3、 if( nodes == (1>>height - 1)) yes else no

​ method2、樹遞迴

舉例所有的可能性:

​ 1、head左、右子樹,

​ 樹高 , 節點數

​ 所以info為樹高、節點數

		Info  process(Node head){
		//base case
		if(head == null){
		return  new Info(0,0);
		}
		//遞迴
		process(head.left);
		process(head.right);
		//處理此次的資訊
		int height  = max(process(head.left).height ,
		process(head.right).height ) + 1;
		int nodes = process(head(left).nodes
		+process(head(right).nodes+1;
		return  new  Info(height  ,nodes);
		}
		
		void isFull(){
			process(head);
			if(  nodes ==  (1>>height  - 1))    
			yes   else  no;
		}
		

3、is完全二叉樹

method1、暴力解法

​ 情況1、有右孩子沒有左孩子

​ 2、有左右孩子不雙全,後序又出現孩子的情況!

​ 其餘情況都是滿足條件

​ 使用寬度優先遍歷,之後使用flag1記錄左右孩子不雙全的情況,出現情況1、2就退出!

method2、樹遞迴方法

​ 舉例所有答案

​ 1、)滿二叉樹

​ 2、)有缺口

​ 1:左樹沒有撐滿,右樹為滿二叉樹

​ 2:左樹撐滿,但是沒有到右樹,左右樹都是滿二叉樹

​ 3:左樹撐滿,右樹為完全二叉樹

​ 轉為數學表示式:

​ 2.1 left.height - right.height = 1

​ 左.isCBT(完全) 右.isFull(滿)

可能會需要的資訊: 樹的結點數,用於判斷isFull。但是沒有必要,因為,當左樹,右樹都是full,且高度差為0,該樹必定為滿二叉樹。base case 時,full 為 true。所以之前的題可以用這個思想去優化!!!

​ 同理2.2 ,2.3都需要上述的height,isFull,isCBT的三個資訊

public static class Info {
		public boolean isFull; //滿
		public boolean isCBT; //完全
		public int height; //高度

		public Info(boolean full, boolean cbt, int h) {
			isFull = full;
			isCBT = cbt;
			height = h;
		}
	}
Info  process(Node head){
		//base case
		if(head == null){
		return new  
		}	
		//遞迴
		Info leftInfo = process(head.left);
		Info rightInfo = process(head.right);
		//處理次次訊息
		int height = max(leftInfo.height ,
		rightInfo.height ) + 1;
		
		boolean isFull =false;
		if(leftInfo.isFull
        &&
		rightInfo.isFull
		&&
		leftInfo.height
        == 
       rightInfo.height){ isFull = true;}
		
		isCBT = false ;
		if(isFull){
			isCBT = true;
		}else{
		//1
		if( leftInfo.isCBT 
		&&  
		rightInfo.isFull
		&&
		leftInfo.height -	
		rightInfo.height ==  1){isCBT = true;}
		//2
		if(leftInfo.isFull
		&&  
		rightInfo.isFull
		&&
		leftInfo.height -	
		rightInfo.height ==  1){isCBT = true;}
		//3
		if(leftInfo.isFull
		&&  
		rightInfo.isCBT
		&&
		leftInfo.height -	
		rightInfo.height ==  0{isCBT = true;}
		}
		return Info(isFull, isCBT, height);

}

4、返回最大距離

​ 給定一棵二叉樹的頭節點head,任何兩個節點之間都存在距離,返回整棵二叉樹的最大距離

1、)最大距離 列舉答案所有可能假設分類:

​ 1、與head無關

​ 需要左最大距離,左max

​ 需要右最大距離,右max

​ 最大距離 = (左max,右max)

​ 2、與head有關

​ 換言之就是倆棵最深樹的距離

​ 最大距離 = 左樹高+1+右樹高

​ 樹高 = max(左數高 ,右樹高) + 1

3種情況

2、)需要資訊

​ 1、樹的高度

​ 2、點的最大距離

Info process(Node x){
    //base case
    if(x == null){
        return  new Info( 0 ,0);
    }
    //遞迴
	Info(x.left);
	Info(x.right);
    //處理本次的資訊sf
    
	height = max(左樹高,右樹高) + 1;
    distance = 左樹高 + 右樹高 + 1 ;
	maxDistance = max(distance,max(Info(x.left).maxDistance,Info(x.right).maxDistance))
       return  new Info(height , maxDistance)
}

剩下的舉例見演算法題!

5、公共父節點

​ 給定一棵二叉樹的頭節點head,和另外兩個節點o1和o2。返回o1和o2的最低公共祖先

​ method1、暴力解

​ 1、使用map記錄每個鍵值對<子節點,父節點>

​ 2、使用set,將a的節點的所有父節點加入set

​ 3、遍歷b的父節點,set.contain(b.父節點) 判斷是否有重複

​ method2、二叉樹遞迴

​ 分析所有答案情況:

​ 1、 o1,o2不在head

​ 2、 o1,o2有一個在head的子樹上 (都沒有交匯)

​ 3、o1,o2都在head的子樹上 (必有交匯點)

​ 1)全在左子樹

​ 2)全在右子樹

​ 3)左右個一個

​ 4)o1 or o2為head

需要的資訊:

樹上有無o1,o2,交匯點

public static class Info {
   //第一個交會的父節點
   public Node ans;
   //發現01
   public boolean findO1;
   //發現02
   public boolean findO2;

   public Info(Node a, boolean f1, boolean f2) {
      ans = a;
      findO1 = f1;
      findO2 = f2;
   }
}
Info process(Node head){
	//base case
	if(head  == null){
	return new Info(null,false,false);
	}
		Info leftInfo = process(head.left);
		Info rightInfo = process(head.right);
	//3資訊
		boolean findO1 = head == o1 || leftInfo.findO1 || rightInfo.findO1;
		boolean findO2 = head == o2 || leftInfo.findO2 || rightInfo.findO2;
	//3資訊整合才是上述簡要概括
	
}