聊聊判斷二叉樹A中是否包含子樹B
Leetcode : https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof
“GitHub : https://github.com/nateshao/leetcode/blob/main/algo-notes/src/main/java/com/nateshao/sword_offer/topic_20_isSubStructure/Solution.java
判斷二叉樹A中是否包含子樹B
“題目描述 :輸入兩棵二叉樹A和B,判斷B是不是A的子結構。(約定空樹不是任意一個樹的子結構)B是A的子結構, 即 A中有出現和B相同的結構和節點值。例如:給定的樹 A:
- 3
- / \
- 4 5
- / \
- 1 2
給定的樹 B:
- 4
- /
- 1
返回 true,因為 B 與 A 的一個子樹擁有相同的結構和節點值。示例 1:
- 輸入:A = [1,2,3], B = [3,1]
- 輸出:false
示例 2:
- 輸入:A = [3,4,5,1,2], B = [4,1]
- 輸出:true
限制:0 <= 節點個數 <= 10000
解題思路:若樹B是樹A的子結構,則子結構的根節點可能為樹A的任意一個節點。因此,判斷樹B是否是樹A的子結構,需完成以下兩步工作:
先序遍歷樹A中的每個節點nA ; (對應函數 isSubStructure(A, B) )
判斷樹A中以nA為根節點的子樹否包含樹B。(對應函數recur(A,B))
算法流程:
“名詞規定:樹 A 的根節點記作 節點 A ,樹 B 的根節點稱為 節點 B 。
recur(A, B) 函數:
1.終止條件:
- 當節點 B為空:說明樹 B 已匹配完成(越過葉子節點),因此返回 true ;
- 當節點 A為空:說明已經越過樹 A 葉子節點,即匹配失敗,返回 false ;
- 當節點 A 和 B 的值不同:說明匹配失敗,返回 false ;
2.返回值:
- 判斷A和B的左子節點是否相等,即recur(A. left, B. left) ;
- 判斷A和B的右子節點是否相等,即recur(A. right,B. right) ;
isSubStructure(A, B)函數:
- 特例處理 :當樹A為空或樹B為空時,直接返回false;
- 返回值 :若樹B是樹A的子結構,則必滿足以下三種情況之一,因此用或|連接;
- 以節點A為根節點的子樹包含樹B,對應recur(A,B);
- 樹B是樹A左子樹的子結構,對應isSubStructure(A. left, B) ;
- 樹B是樹A右子樹的子結構,對應isSubStructure(A. right, B) ;
以讓 2. 3.實質上是在對樹A做先序遍歷。
復雜度分析:
- 時間復雜度O(MN): 中M,N分別為樹A和樹B的節點數量;先序遍歷樹A占用0(M),每次調用recur(A, B)判斷占用O(N)。
- 空間復雜度O(M):
- 當樹A和樹B都退化為鏈表時,遞歸調用深度最大。
- 當M≤N時,遍歷樹A與遞歸判斷的總遞歸深度為M ;
- 當M> N時,最差情況為遍歷至樹A葉子節點,此時總遞歸深度為M。
- package com.nateshao.sword_offer.topic_20_isSubStructure;
- /**
- * @date Created by 邵桐杰 on 2021/11/23 19:19
- * @微信公眾號 程序員千羽
- * @個人網站 www.nateshao.cn
- * @博客 https://nateshao.gitee.io
- * @GitHub https://github.com/nateshao
- * @Gitee https://gitee.com/nateshao
- * Description: 判斷二叉樹A中是否包含子樹B
- */
- class Solution {
- /**
- * 精選解答
- * @param A
- * @param B
- * @return
- */
- public static boolean isSubStructure1(TreeNode A, TreeNode B) {
- return (A != null && B != null) && (recur1(A, B) || isSubStructure1(A.left, B) || isSubStructure1(A.right, B));
- }
- public static boolean recur1(TreeNode A, TreeNode B) {
- if (B == null) return true;
- if (A == null || A.val != B.val) return false;
- return recur1(A.left, B.left) && recur1(A.right, B.right);
- }
- /*********************************** 法二 *********************************************/
- //遍歷A的每一個節點
- public boolean isSubStructure(TreeNode A, TreeNode B) {
- if (A == null || B == null) return false;//約定空樹不是任意一個樹的子結構
- return recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
- }
- //同時遍歷A和B的相同位置節點
- boolean recur(TreeNode A, TreeNode B) {
- //當B某個節點為null,則無需比較了,直接返回true,比較其他節點
- if (B == null) return true;
- //如果相同位置的兩個節點不相同,則返回false,不用再繼續比較了
- if (A == null || A.val != B.val) return false;
- //繼續往下遍歷比較
- return recur(A.left, B.left) && recur(A.right, B.right);
- }
- public class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) {
- val = x;
- }
- }
- }
參考鏈接:https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof/solution/mian-shi-ti-26-shu-de-zi-jie-gou-xian-xu-bian-li-p