(尊重勞動成果,轉載請註明出處:https://yangwenqiang.blog.csdn.net/article/details/105928523
冷血之心的博客)
這段時間完成了職業生涯第一次跳槽,對算法題目有了一個更深的認識和理解,這裏將二叉樹常見的面試題目以及解法補充完善。
二叉樹基礎題(六):樹的子結構&二叉搜索樹的判斷&鏡像二叉樹
今天我們再來看三道二叉樹相關的基礎題目吧,如下所示:
- 樹的子結構
- 二叉搜索樹
- 鏡像二叉樹
題目一:樹的子結構
輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)
思路:
1、首先設置標誌位result = false,因爲一旦匹配成功result就設爲true,剩下的代碼不會執行,如果匹配不成功,默認返回false
2、遞歸思想,如果根節點相同則遞歸調用DoesTree1HaveTree2(),如果根節點不相同,則判斷tree1的左子樹和tree2是否相同,再判斷右子樹和tree2是否相同
3、注意null的條件,HasSubTree中,如果兩棵樹都不爲空才進行判斷,DoesTree1HasTree2中,如果Tree2爲空,則說明第二棵樹遍歷完了,即匹配成功,tree1爲空有兩種情況:
- 如果tree1爲空&&tree2不爲空說明不匹配,
- 如果tree1爲空,tree2爲空,說明匹配。
代碼實現如下:
public class Main {
public boolean HashSubtree(TreeNode root1, TreeNode root2){
boolean result = false;
//當Tree1和Tree2都不爲null的時候,才進行比較。否則直接返回false
if(root1!=null&&root2!=null){
//如果找到了對應Tree2的根節點的點
if(root1.val==root2.val){
//以這個根節點爲爲起點判斷是否包含Tree2
result = DoesTree1haveTree2(root1,root2);
}
//如果找不到,那麼就再去root的左兒子當作起點,去判斷時候包含Tree2
if(!result)
result = HashSubtree(root1.left, root2);
//如果還找不到,那麼就再去root的右兒子當作起點,去判斷時候包含Tree2
if(!result)
result = HashSubtree(root1.right, root2);
}
return result;
}
private boolean DoesTree1haveTree2(TreeNode root1, TreeNode root2) {
//如果Tree2已經遍歷完了都能對應的上,返回true
if(root2==null)
return true;
//如果Tree2還沒有遍歷完,Tree1卻遍歷完了。返回false
if(root1==null&&root2!=null)
return false;
//如果其中有一個點沒有對應上,返回false
if(root1.val!=root2.val)
return false;
//如果根節點對應的上,那麼就分別去子節點裏面匹配
return DoesTree1haveTree2(root1.left, root2.left)
&&DoesTree1haveTree2(root1.right, root2.right);
}
}
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
題目二:是否是二叉搜索樹
給定一個二叉樹,判斷其是否是一個有效的二叉搜索樹。
二叉搜索樹的定義如下:
- 節點的左子樹只包含小於當前節點的數。
- 節點的右子樹只包含大於當前節點的數。
- 所有左子樹和右子樹自身必須也是二叉搜索樹。
看到這裏,也許大家很easy就可以寫出如下的錯誤代碼:
public boolean isValidBST(TreeNode root) {
if (root == null)
return true;
if (root.left != null && root.val <= root.left.val)
return false;
if (root.right != null && root.val >= root.right.val)
return false;
return isValidBST(root.left) && isValidBST(root.right);
}
這個代碼有問題嗎?有嗎?當然有問題了。我們的當前節點的值要大於左邊子樹的所有節點,而不僅僅是其一個左子樹節點,右邊也是同樣的道理。比如下邊所示並不是一個合法的二叉搜索樹,但是我們的算法會返回true
怎麼辦呢?
這個時候需要使用二叉樹操作中經常需要使用的方法了,重載當前的函數,傳入更多的參數,使得我們可以擁有更多的信息,最後纔是遞歸調用!
正確的代碼實現如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root,null,null);
}
// 使用輔助函數,增加函數參數列表,在參數中攜帶額外信息
private boolean isValidBST(TreeNode root, TreeNode min,TreeNode max){
if(root==null)
return true;
if(min!=null&&root.val<=min.val)
return false;
if(max!=null&&root.val>=max.val)
return false;
return isValidBST(root.left,min,root)&&isValidBST(root.right,root,max);
}
}
題目三:鏡像二叉樹(二叉樹的翻轉)
二叉樹的鏡像:操作給定的二叉樹,將其變換爲原二叉樹的鏡像。
思路:
這道題目還算比較簡單吧,其實也挺難的,Homebrew 的作者Max Howell面試被 Google
拒啦,因爲他不會翻轉二叉樹。是不是很悲劇?
這道題目可以給出兩個解決方法:
- 原地交換當前節點的左右節點
- 新建一顆二叉樹
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
public class Solution {
// Mirror求出的即是當前二叉樹的鏡像
public void Mirror(TreeNode root) {
if (root == null)
return;
// 交換當前節點的左右節點
TreeNode tmpNode = root.left;
root.left = root.right;
root.right = tmpNode;
Mirror(root.left);
Mirror(root.right);
}
// 獲取鏡像二叉樹(不改變原二叉樹,重新生成了一個其鏡像二叉樹)
private TreeNode getMirror(TreeNode pRoot) {
if (pRoot == null) {
return null;
}
TreeNode root = new TreeNode(pRoot.val);
root.right = getMirror(pRoot.left);
root.left = getMirror(pRoot.right);
return root;
}
}
總結:
二叉樹相關的題目的一個技巧就是重載一個函數用來遞歸,可以傳入額外的參數,獲取更多的信息。另外就是二叉樹的遞歸解法中,我們只要定義一個遞歸函數,並且處理好當前節點要處理的事情即可,別的都交給遞歸函數,認爲其已經給我們解決了問題,切莫在腦子裏進行壓棧和出棧的操作,因爲我們的腦子都不夠用哈~
就比如說二叉樹的鏡像算法中,我們只需要確定下遞歸結束條件,處理好當前節點的事情(交換),然後再分別遞歸左右子樹即可。
後續我會繼續更新二叉樹相關基礎題目,感興趣的同學可以持續關注交流~
注意啦,注意啦~
歡迎大家關注我的牛客專欄:《Java開發崗面試題全解析》 ,點擊圖片查看詳情。
Java開發崗高頻面試題全解析,專欄共計32節,已經全部更新完畢。
專欄分9個模塊來對Java崗位面試中的知識點進行解析,包括通用面試技能,Java基礎,Java進階,網絡協議,常見框架以及算法,設計模式等。
專欄串點成面的解析每個面試題背後的技術原理,由淺入深,循序漸進,力爭讓大家掌握面試題目的背後的技術原理,摒棄背題模式的陋習。
如果對你有幫助,記得點贊哈,歡迎大家關注我的博客,關注公衆號(文強的技術小屋),學習更多技術知識,一起遨遊知識海洋~