題目描述
輸入兩棵二叉樹A和B,判斷B是不是A的子結構。我們約定空樹不是任意一個樹的子結構。
基本思路
要查找樹A是否存在和樹B結構一樣的子樹,我們可以分成兩步:第一步在樹A中找到和樹B的根節點的值一樣的節點R,第二步再判斷樹A中以R為根節點的子樹是不是包含和樹B一樣的結構。

如上圖所示:首先我們試着在樹A中找到值為8(樹B的根節點的值)的節點。從樹A的根節點開始遍歷,我們發現它的根節點就是8。接着我們就去判斷樹A的根節點下面的子樹是不是含有和樹B一樣的結構。在樹A中,根節點的左子節點的值是8,而樹B的根節點的左子節點是9,對應的兩個節點不同。
因此,我們仍需要遍歷樹A,接着查找值為8的節點。我們在樹的第二層找到了一個值為8的節點,然后進行第二步判斷,即判斷這個節點下面的子樹是否含有和樹B一樣結構的子樹。於是我們遍歷這個節點下面的子樹,先后得到兩個子節點9和2,這和B樹的結構完全相同。此時我們在樹A中找到了一個和樹B的結構一樣的子樹,因此樹B是樹A的子結構。
第一步在樹A中查找與根節點一樣的節點,實際上就是樹的遍歷,可以采用遞歸的方式,代碼如下:
public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root2==null) return false; if(root1==null && root2!=null) return false; boolean flag = false; if(root1.val==root2.val){ flag = isSubTree(root1,root2); } if(!flag){ flag = HasSubtree(root1.left, root2); if(!flag){ flag = HasSubtree(root1.right, root2); } } return flag; }
第二步是判斷樹A中以R為根節點的子樹是不是和樹B具有相同的結構。同樣,我們也可以用遞歸的思路來考慮:如果節點R的值和樹B的根節點不相同,則以R為根節點的子樹和樹B肯定不具有相同的結點;如果它們的值相同,則遞歸地判斷它們各自的左右節點的值是不是相同。遞歸的終止條件是我們到達了樹A或者樹B的葉節點,代碼如下:
private boolean isSubTree(TreeNode root1, TreeNode root2) { if(root2==null) return true; if(root1==null && root2!=null) return false; if(root1.val==root2.val){ return isSubTree(root1.left, root2.left) && isSubTree(root1.right, root2.right); }else{ return false; } }
上述代碼有多處判斷節點是不是NULL,這樣做是為了避免試圖訪問空節點而造成的程序崩潰,同時設置了遞歸調用的退出條件。
