劍指OFFER樹相關
注:順序是先篩選分類再按LeeCode上的通過率排的,每題最後的總結代碼都是在LeeCode上跑過的,應該沒啥問題。但是思路中的代碼都是直接在CSDN編輯器裏徒手敲的,若有筆誤還煩請告知,蟹蟹~
55-1 二叉樹的深度
思路是使用遞歸,說到遞歸,立馬寫下如下思路:
- 方法想要幹什麼?
- 方法的終止條件是什麼?以此確定終止條件;
- 方法的等價關係是什麼?以此確定返回值。
立馬寫下如下三個詞:
- 終止條件
- 遞推關係
- 返回值
然後開始分析:
- 首先這個方法想要計算以入參root爲根節點的樹的深度,那麼方法的返回值即爲此樹的深度;
- 其次這個方法的終止條件是當傳入的root爲空時,返回深度爲0;
- 最後這個方法的等價關係是root節點的深度等於:root左節點的深度與root右節點的深度相較而言更大的那個深度加上1。
分析結束,將思路轉爲代碼段在草稿紙上寫:
終止條件:
if(root == null){
return 0;
}
遞推關係:
depth = Math.max(maxDepth(root.left).maxDepth(root.right)) + 1;
返回值:
return dpeth;
整理成代碼:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
}
27 二叉樹的鏡像
開始分析:
- 首先這個方法要將以入參root爲根節點的樹鏡像變換;
- 其次當root爲空的時候停止遍歷,返回
null
; - 最後遞歸關係是將root左節點的鏡像放在右節點上,將root右節點的鏡像放在左節點上,即可完成root的鏡像。
終止條件:
if(root == null){
return null;
}
遞推關係:
TreeNode tmp = root.left;
root.left = mirrorTree(root.right);
root.right = mirrorTree(tmp);
返回值:
return root;
整理成代碼:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode tmp = root.left;
root.left = mirrorTree(root.right);
root.right = mirrorTree(tmp);
return root;
}
}
54 二叉搜索樹的第K大節點
開始分析:
- 首先這個方法是求第K大個節點對應的值;
- 其次當傳入節點爲
null
時返回,或者找到了第K大節點後返回; - 最後遞歸關係是使用反中序遍歷的方法遍歷這顆二叉搜索樹,很關鍵的一點是看到二叉搜索樹首先想到中序遍歷,因爲二叉搜索樹的中序遍歷結果是從小到大有序的數組,具體說來就是先看右子樹有沒有第K大,沒有的話看自己是不是第K大,最後再看左子樹有沒有第K大。
知識點:看到二叉搜索樹想到中序遍歷
終止條件:
if(root == null){
return;
}
if(count == 0){
return;
}
遞推關係:
helper(root.right);
if(--count == 0){
res = root.val;
}
helper(root.left);
返回值:
//res直接寫在類內上,所有方法共用,不用返回
整理成代碼:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private int count = 0,res = 0;
public int kthLargest(TreeNode root, int k) {
count = k;
helper(root);
return res;
}
private void helper(TreeNode root){
if(root == null){
return;
}
helper(root.right);
if(count == 0){
return;
}
if(--count == 0){
res = root.val;
}
helper(root.left);
}
}
32-II 從上到下打印二叉樹
開始分析:
此題需要用到層次遍歷,層次遍歷也可以被稱爲二叉樹的廣度優先遍歷BFS,說道廣度優先遍歷,就要想到我們需要維護一個隊列,通過控制節點在隊列的進出來控制遍歷的節奏。
二叉樹BFS的大致框架,更多細節在具體實現的代碼註釋中有講到:
//初始化一個隊列並把首節點放進隊列裏
Queue<TreeNode> queue = new LinkedList<>(){{add(root);}};
//當隊列不爲空的時候循環
while(!queue.isEmpty()){
//一層層算賬
for(int i = queue.size(); i > 0; i--){
//先把本層節點給poll出來
TreeNode node = queue.poll();
//再把與本層相連的下層左右節點給塞進去
if(node.left != null){
queue.add(node.left);
}
if(node.right != null){
queue.add(node.right);
}
}
}
知識點:廣度優先,先建隊列,每層poll出,下層add進。
因爲這題打印結果呈現每層單獨一個ArrayList的結果,所以要在每層的循環中開一個ArrayList接一下即可。總體框架還是能看出來的。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
//判斷特殊情況
if(root == null){
return new ArrayList<>();
}
//一個ArrayList承載最後的結果
List<List<Integer>> res = new ArrayList<>();
//一個Queue->LinkedList承載每一層的節點,初始化爲首層的root
Queue<TreeNode> queue = new LinkedList<>(){{add(root);}};
//若queue爲空,則說明所有的節點都處理完畢,可以輸出結果了
//這裏用queue.isEmpty(),不能用queue==null
while(!queue.isEmpty()){
//緩存每層的數據,這裏用List<Integer>是爲了每層直接接上最後的結果
List<Integer> tmp = new ArrayList<>();
//一個for,從queue.size()開始,這很關鍵,
//用for(int i = 0; i < queue.size(); i++)的話,則會報錯
//因爲隊列的長度是在變化的,應該首先就指定好,這樣才能保證每次循環只出一層的數據
for(int i = queue.size();i > 0; i--){
//隊列先進先出,進是add出是poll
TreeNode father = queue.poll();
//記得先判斷是否爲空再添加進隊列中,不然會報空指針異常
if(father.left != null){
//把左孩子加入進去,等待其在下一層被poll出來
queue.add(father.left);
}
//右孩子同理
if(father.right != null){
queue.add(father.right);
}
//把poll出的節點的值存進ArrayList中
tmp.add(father.val);
}
//把一層的ArrayList值存進最後的結果中
res.add(tmp);
}
return res;
}
}
07 重建二叉樹
先序遍歷:根左右
中序遍歷:左根右
1:前序遍歷的首節點爲root
int rootVal = preorder[0];
2:根據拿到的root去中序遍歷裏尋找對應的root
int rootIndex = 0;
for(int i = 0; i < inorder.length; i++){
if(rootVal == inorder[i]){
rootIndex = i;
break;
}
}
3-4:在中序遍歷中找到root之後,它的左右即爲當前root節點的左子樹和右子樹
//inorder的左邊:
Arrays.copyOfRange(inorder, 0, rootIndex);
//inorder的右邊:
Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length);
注意copyOfRange的取值範圍是左閉右開,可以畫圖觀察,Java裏很多這種取值的操作都是左閉右開的,想想str.substring(閉,開);
5-6:根據我們得到的左右子樹,去前序遍歷找左右子樹的段落
//preorder的左邊:
Arrays.copyOfRange(preorder, 1, 1 + rootIndex);
//preorder的右邊:
Arrays.copyOfRange(preorder, 1 + rootIndex, preorder.length);
7-8:根據前序遍歷的特點,我們所找的段落的首節點就是直接連着root的左孩子與右孩子
root.left = buildTree(preorder的左邊,inorder的左邊);
root.right = buildTree(preorder的右邊,inorder的右邊);
至此我們就可以進行遞歸操作了。
有沒有發現樹的遞歸操作很多時候都是在root.left和root.right的時候用等於接上的,這種格式可以多多考慮:
root.left = 遞歸左子樹;
root.right = 遞歸右子樹;
整理成代碼:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
if(n == 0){
return null;
}
int rootVal = preorder[0],rootIndex = 0;
for(int i = 0; i < n; i++){
if(rootVal == inorder[i]){
rootIndex = i;
break;
}
}
TreeNode root = new TreeNode(rootVal);
root.left = buildTree(Arrays.copyOfRange(preorder,1,1 + rootIndex),Arrays.copyOfRange(inorder,0,rootIndex));
root.right = buildTree(Arrays.copyOfRange(preorder,1+rootIndex,n),Arrays.copyOfRange(inorder,rootIndex+1,n));
return root;
}
}
68-I 二叉搜索樹的最近公共祖先
- 方法的作用是用來找root節點爲根節點的樹裏指定兩個節點的公共祖先;
- 當傳入爲
null
時返回; - 根據二叉搜索樹的性質,若是p與q一個比root大一個比root小,那麼就說明root在兩個節點之間,否則就在根據root與p、q的大小來判斷左邊或者右邊。
終止條件:
if(root == null){
return null;
}
遞推關係:
if(root.val > p.val && root.val > q.val){
return lowestCommonAncestor(root.left, p, q);
}else if(root.val < p.val && root.val < q.val){
return lowestCommonAncestor(root.right, p, q);
}
返回值:
return root;
整理成代碼:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(root.val > p.val && root.val > q.val){
return lowestCommonAncestor(root.left, p, q);
}else if(root.val < p.val && root.val < q.val){
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
68-II 二叉樹的最近公共祖先
- 方法的作用是看p或q在不在,若在則返回p或q,若不在則返回null
- 當
root == null
的時候返回null
,root == p
的時候返回p
,root == q
的時候返回q
- 當左子樹爲
null
說明兩個都在右邊,當右子樹爲null
說明兩個都在左邊,只有左右子樹都不爲null
的時候該root纔是公共祖先,返回這個root,層層上傳。
終止條件
if(root == null){
return null;
}
if(root == p || root == q){
return root;
}
遞推關係
TreeNode leftNode = lowestCommonAncestor(root.left,p,q);
TreeNode rightNode = lowestCommonAncestor(root.right,p,q);
if(leftNode == null){
return rightNode;
}
if(rightNode == null){
return leftNode;
}
返回值
return root;
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(root == p || root == q){
return root;
}
TreeNode leftNode = lowestCommonAncestor(root.left,p,q);
TreeNode rightNode = lowestCommonAncestor(root.right,p,q);
if(leftNode == null){
return rightNode;
}
if(rightNode == null){
return leftNode;
}
return root;
}
}
32-I 從上到下打印二叉樹
這題爲啥會比32-II做出來的人少…我蒙了,就是廣度優先遍歷的板子就完事了。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
//特殊邊界要提前考慮到
if(root == null){
return new int[0];
}
LinkedList<TreeNode> queue = new LinkedList<>(){{add(root);}};
ArrayList<Integer> res = new ArrayList<>();
while(!queue.isEmpty()){
for(int i = queue.size(); i > 0; i--){
TreeNode tmp = queue.poll();
res.add(tmp.val);
if(tmp.left != null){
queue.add(tmp.left);
}
if(tmp.right != null){
queue.add(tmp.right);
}
}
}
//這裏返回值是int[],再遍歷一遍傳過去吧,卑微
int[] n = new int[res.size()];
for(int j = 0; j < res.size(); j++){
n[j] = res.get(j);
}
return n;
}
}
32-III 從上到下下打印二叉樹
你要是一路看下來的話這玩意是第三個BFS題了,加個reverse就完事了。這題我們來嘮嘮返回值的事,這個方法讓我們返回的是List<List<Integer>>
這麼個玩意,當root == null
的時候,我們應該怎麼看返回個啥呢?答案是看它最外層是啥,它最外層是個List<>
,那我們就
if(root == null){
return ArrayList<>();
//return LinkedList<>();一樣也行
}
這玩意說難也不難,就是有時候會一下鑽牛角尖裏,不造返回啥了,寫出來防止忘記。
還有一個好玩的操作是判斷奇偶數,這麼寫其實也不會快(因爲聽說你用取餘的時候,JAVA底層已經優化成這種寫法了),但是秀呀哈哈。
//奇數
if((i & 1) == 1){
...
}
//偶數
if((i & 1) == 0){
...
}
最後上個代碼:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null){
return new ArrayList<>();
}
LinkedList<List<Integer>> res = new LinkedList<>();
LinkedList<TreeNode> queue = new LinkedList<>(){{add(root);}};、
//設置個層數
int floor = 0;
while(!queue.isEmpty()){
ArrayList<Integer> tmp = new ArrayList<>();
for(int i = queue.size(); i > 0; i--){
TreeNode node = queue.poll();
tmp.add(node.val);
if(node.left != null){
queue.add(node.left);
}
if(node.right!= null){
queue.add(node.right);
}
}
//當奇數層時需要翻轉
if((floor & 1) == 1){
Collections.reverse(tmp);
}
res.add(tmp);
//層數++
floor++;
}
return res;
}
}
55-II 平衡二叉樹
emmm這題寫的有點醜,雖然最後蜜汁跑出了99.96%和100%的成績…
思路就是遞歸,感覺不用之前那麼一板一眼的分析了,有點感覺了,就直接說我怎麼想的吧。首先拿到左邊和右邊的高度,兩個一減取個絕對值,要是這個值大於1呢就說明剛好在你正在處理的root節點完球了,返回false
就完事了,不然呢,就返回左子樹有沒有完球 && 右子樹有沒有完球
。還有一個問題是我們怎麼知道左邊和右邊的高度是多少呢?再寫個函數,像“55-1 二叉樹的深度”那題那樣遞歸一下就完事了。
所以我寫了兩個遞歸咋跑到99.96%的?我看大佬們寫的比我簡潔多了。
我好像發現了做遞歸題的idea:
你:算法之神,你只要告訴我前一次_______,我就能給你整出我這個________。
算法之神:小夥子牛逼哦,那我給你前一次__________的結果,你算吧。
你:現在只要把前一次_________xxxxx,然後xxxxx,最後返回的_______就是我這個________了,牛逼不。
算法之神:牛逼哦~
你:算法之神,你只要告訴我前一個節點是不是平衡二叉樹,我就能給你整出我這個節點是不是平衡二叉樹。
算法之神:小夥子牛逼哦,那我給你前一個節點是不是平衡二叉樹的結果,你算吧。
你:現在只要看左邊是不是平衡二叉樹,再看右邊是不是平衡二叉樹,要是兩邊都平衡,那我這個節點就是平衡二叉樹,要是有一邊不是,那我這個節點就不是平衡二叉樹。牛逼不。
算法之神:牛逼哦~
順便記一下絕對值方法:
Math.abs(i);
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
//空樹肯定平衡
if(root == null){
return true;
}
//拿左右子樹高度
int leftNode = treeHeight(root.left);
int rightNode = treeHeight(root.right);
//瞅瞅自己這個節點上兩個差有沒有大於1,大於了就麻溜的false
if(Math.abs((leftNode - rightNode)) > 1){
return false;
}
//瞅瞅左邊,瞅瞅右邊
return isBalanced(root.left) && isBalanced(root.right);
}
public int treeHeight(TreeNode root){
//空了高度就是0了
if(root == null){
return 0;
}
//左邊高度和右邊高度拿到
int leftHeight = treeHeight(root.left);
int rightHeight = treeHeight(root.right);
//現在的高度就是左右高度高的那嘎達加1
return Math.max(leftHeight,rightHeight) + 1;
}
}
28 對稱的二叉樹
鏡像就是左邊的左邊等於右邊的右邊,左邊的右邊等於右邊的左邊。
我們造一個遞歸方法,表示該樹是否鏡像,只要告訴我左邊的左邊和右邊的右邊是不是鏡像,左邊的右邊和右邊的左邊是不是鏡像,我就能告訴你當前節點是不是鏡像,我只要再判斷當前節點的左右是一樣的即可。
判斷左右節點一樣之前要保證他們都不是null或者都是null,不然會報空指針,用這樣的模板即可:
//先判斷左右是不是都是null
if(left == null && right == null){
return true;
}
//已經排除左右都是null的情況下,任意一邊爲null都說明left和right不相等
if(left == null || right == null){
return false;
}
代碼如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null){
return true;
}
return helper(root.left,root.right);
}
private boolean helper(TreeNode left,TreeNode right){
if(left == null && right == null){
return true;
}
if(left == null || right == null){
return false;
}
//除去null,還有一種false是左右不相等
if(left.val != right.val){
return false;
}
//算法之神告訴了我左左右右和左右右左是不是鏡像
//如果左右相等,那本節點的結果就是 左左右右 && 左右右左 的結果
return helper(left.left,right.right) && helper(left.right,right.left);
}
}
34 二叉樹中和爲某一值的路徑
這題是傳說中的回溯(麼?我也不知道),我死在淺拷貝還是深拷貝上了,絕望調試了半天…這地方是個深坑,沒踩過十有八九是會忽略的,這題就來嘮嘮這玩意。
先說整體思路吧,一個List<List<Integer>>
來接最後的結果,一個List<Integer>
來接(這裏插一句,看我頂上一開始申明的LinkedList<Integer>
就知道我想拿棧來做這玩意了,結果發現棧做出來結果是倒序的它不認,加個Collections.reverse()
直接給我幹掉2ms,拉倒吧還是用隊列做吧。),然後就是一個遞歸函數。
嘮嘮這個遞歸函數,首先碰到null返回,其次在本節點中的任務是先把本節點的值加在統計本條線路的值中,然後把本節點塞進隊列裏,再去查看本節點是不是葉子,如果是葉子的話就看和我們想要的值是否相等,相等就深拷貝一下我們記錄的這條線路,然後把本節點的值減掉,把本節點吐出來;要不是葉子節點就向左向右遞歸,注意遞歸一路彈回來到這之後還是要把本節點吐出來的,所以不如直接把吐出來放在最後,少打一句話舒坦三十秒。
提一嘴這個函數,用隊列的時候可以用上:
LinkedList<Integer> linkedlist = new LinkedList<>();
linkedlist.removeLast(); //刪除隊列的最後一個元素
先看代碼再說坑,代碼如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<List<Integer>> res;
LinkedList<Integer> ways;
int sum = 0;
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if(root == null){
return new ArrayList<>();
}
//前期準備
res = new ArrayList<>();
ways = new LinkedList<>();
this.sum = sum;
//調用遞歸方法
helper(root,0);
return res;
}
private void helper(TreeNode root,int waySum){
if(root == null){
return;
}
//本節點到了,先給他把值加上,塞隊裏
waySum += root.val;
ways.add(root.val);
//瞅瞅本節點是不是葉子節點啊,是葉子的話總值對不對啊
if(waySum == sum && root.left == null && root.right == null){
//深拷貝的牌面還是要有的,把當前路徑深拷貝到結果隊列裏
res.add(new LinkedList<>(ways));
}else{
//不是葉子,下面還有節點,藥不能停,向左向右繼續
helper(root.left,waySum);
helper(root.right,waySum);
}
//把最後一位移除收尾,對於葉子來說是把葉子移出;
//對於非葉子來說是遞歸結束的時候彈到本節點時把本節點移出
ways.removeLast();
}
}
然後就要說拷貝這事了,我一開始在葉子節點那是這麼寫的:
if(waySum == sum && root.left == null && root.right == null){
res.add(ways);
}
然後就麻了,得到的結果是這樣的:
[[],[]]
我尋思找出來路徑的個數也對了啊,怎麼不顯示路徑呢,我也add(ways)
了啊。最後發現我這樣寫是淺拷貝,拷貝的只是指向ways
的一個指針,所以ways
一會add(root.val)
的一會removeLast()
的,我想輸出的值也在跟着變了。
淺拷貝(Shallow Copy):
①對於數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值複製一份給新的對象。因爲是兩份不同的數據,所以對其中一個對象的該成員變量值進行修改,不會影響另一個對象拷貝得到的數據。
②對於數據類型是引用數據類型的成員變量,比如說成員變量是某個數組、某個類的對象等,那麼淺拷貝會進行引用傳遞,也就是隻是將該成員變量的引用值(內存地址)複製一份給新的對象。因爲實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響到另一個對象的該成員變量值。
所以這時候要深拷貝一下,直接新建一個LinkedList<>()
然後把ways
裏的值拷貝過去就完事了。
if(waySum == sum && root.left == null && root.right == null){
res.add(new LinkedList<>(ways));
}
深拷貝(Deep Copy):
相對於淺拷貝而言,對於引用類型的修改,並不會影響到對應的copy對象的值。
每一層的每個對象都進行淺拷貝=深拷貝。
來做個總結:
以後出現結果個數正確、內容錯誤或消失的時候,可以考慮是否是淺拷貝導致的。
37 序列化二叉樹
思路是用BFS做序列化和反序列化,主要還是細心,很多小細節調了不少次,還有就是Sting和Integer的轉換注意下,最後注意一下String判相等還是用equals()
吧,怎麼着都方便點。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root == null){
return "";
}
Queue<TreeNode> queue = new LinkedList<>(){{add(root);}};
StringBuilder sb = new StringBuilder();
sb.append("[");
while(!queue.isEmpty()){
for(int i = queue.size(); i > 0; --i){
TreeNode tmp = queue.poll();
if(tmp != null){
sb.append(tmp.val + ",");
queue.add(tmp.left);
queue.add(tmp.right);
}else{
sb.append("null,");
}
}
}
sb.append("]");
return sb.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data == "" ){
return null;
}
data = data.substring(1,data.length() - 1);
String[] strs = data.split(",");
int index = 0;
TreeNode root = new TreeNode(Integer.parseInt(strs[0]));
Queue<TreeNode> queue = new LinkedList<>(){{add(root);}};
index++;
while(!queue.isEmpty()){
TreeNode node = queue.poll();
if(!strs[index].equals("null")){
node.left = new TreeNode(Integer.parseInt(strs[index]));
queue.add(node.left);
}
index++;
if(!strs[index].equals("null")){
node.right = new TreeNode(Integer.parseInt(strs[index]));
queue.add(node.right);
}
index++;
}
return root;
}
}
// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));
26 樹的子結構
首先需要遞歸的是從本層節點開始,是否有B樹的子結構,這個需要一個對比是否是子結構的遞歸,然後我們還需要一個遞歸是從本層節點的左右節點開始,是否有B樹的子結構,所以這題是雙重遞歸。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A == null || B == null){
return false;
}
//遞歸A的節點
return helper(A,B) || isSubStructure(A.left,B) || isSubStructure(A.right,B);
}
//遞歸A某節點向下的樹與B樹是否一致
private boolean helper(TreeNode A, TreeNode B){
if(B == null){
return true;
}
if(A == null){
return false;
}
return A.val == B.val && helper(A.left,B.left) && helper(A.right,B.right);
}
}
到此爲止樹的部分就結束啦~求個關注啵啵啵(●´З`●)