劍指Offer面試題:17.樹的子結構
一、題目:樹的子結構
題目:輸入兩棵二叉樹A和B,判斷B是不是A的子結構。例如下圖中的兩棵二叉樹,由於A中有一部分子樹的結構和B是一樣的,因此B是A的子結構。
該二叉樹的節點定義如下,這裡使用C#語言描述:
public class BinaryTreeNode { public int Data { get; set; } public BinaryTreeNode leftChild { get; set; } public BinaryTreeNode rightChild { get; set; } public BinaryTreeNode(int data) { this.Data = data; } public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right) { this.Data = data; this.leftChild = left; this.rightChild = right; } }
二、解題思路
2.1 核心步驟
要查詢樹A中是否存在和樹B結構一樣的子樹,我們可以分成兩步:
Step1.在樹A中找到和B的根結點的值一樣的結點R;
Step2.判斷樹A中以R為根結點的子樹是不是包含和樹B一樣的結構。
很明顯,這是一個遞迴的過程。
2.2 程式碼實現
public static bool HasSubTree(BinaryTreeNode root1, BinaryTreeNode root2) { bool result = false; if (root1 != null && root2 != null) { if (root1.Data == root2.Data) { result = DoesTree1HasTree2(root1, root2); } // 從根節點的左子樹開始匹配Tree2 if (!result) { result = HasSubTree(root1.leftChild, root2); } // 如果左子樹沒有匹配成功則繼續在右子樹中繼續匹配Tree2 if (!result) { result = HasSubTree(root1.rightChild, root2); } } return result; } private static bool DoesTree1HasTree2(BinaryTreeNode root1, BinaryTreeNode root2) { if (root2 == null) { // 證明Tree2已經遍歷結束,匹配成功 return true; } if (root1 == null) { // 證明Tree1已經遍歷結束,匹配失敗 return false; } if (root1.Data != root2.Data) { return false; } // 遞迴驗證左子樹和右子樹是否包含Tree2 return DoesTree1HasTree2(root1.leftChild, root2.leftChild) && DoesTree1HasTree2(root1.rightChild, root2.rightChild); }
三、單元測試
為了方便測試,這裡封裝了一個設定指定根節點的左孩子和右孩子節點的方法:SetSubTreeNode
public void SetSubTreeNode(BinaryTreeNode root, BinaryTreeNode lChild, BinaryTreeNode rChild) { if (root == null) { return; } root.leftChild = lChild; root.rightChild = rChild; }View Code
3.1 功能測試
// 01.樹中結點含有分叉,樹B是樹A的子結構 // 8 8 // / \ / \ // 8 7 9 2 // / \ // 9 2 // / \ // 4 7 [TestMethod] public void HasSubTreeTest1() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(7); BinaryTreeNode nodeA4 = new BinaryTreeNode(9); BinaryTreeNode nodeA5 = new BinaryTreeNode(2); BinaryTreeNode nodeA6 = new BinaryTreeNode(4); BinaryTreeNode nodeA7 = new BinaryTreeNode(7); SetSubTreeNode(nodeA1, nodeA2, nodeA3); SetSubTreeNode(nodeA2, nodeA4, nodeA5); SetSubTreeNode(nodeA5, nodeA6, nodeA7); BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(2); SetSubTreeNode(nodeB1, nodeB2, nodeB3); Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), true); } // 02.樹中結點含有分叉,樹B不是樹A的子結構 // 8 8 // / \ / \ // 8 7 9 2 // / \ // 9 3 // / \ // 4 7 [TestMethod] public void HasSubTreeTest2() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(7); BinaryTreeNode nodeA4 = new BinaryTreeNode(9); BinaryTreeNode nodeA5 = new BinaryTreeNode(3); BinaryTreeNode nodeA6 = new BinaryTreeNode(4); BinaryTreeNode nodeA7 = new BinaryTreeNode(7); SetSubTreeNode(nodeA1, nodeA2, nodeA3); SetSubTreeNode(nodeA2, nodeA4, nodeA5); SetSubTreeNode(nodeA5, nodeA6, nodeA7); BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(2); SetSubTreeNode(nodeB1, nodeB2, nodeB3); Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), false); }
3.2 特殊輸入測試
// 03.樹中結點只有左子結點,樹B是樹A的子結構 // 8 8 // / / // 8 9 // / / // 9 2 // / // 2 // / // 5 [TestMethod] public void HasSubTreeTest3() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(9); BinaryTreeNode nodeA4 = new BinaryTreeNode(2); BinaryTreeNode nodeA5 = new BinaryTreeNode(5); nodeA1.leftChild = nodeA2; nodeA2.leftChild = nodeA3; nodeA3.leftChild = nodeA4; nodeA4.leftChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(2); nodeB1.leftChild = nodeB2; nodeB2.leftChild = nodeB3; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), true); } // 04.樹中結點只有左子結點,樹B不是樹A的子結構 // 8 8 // / / // 8 9 // / / // 9 3 // / // 2 // / // 5 [TestMethod] public void HasSubTreeTest4() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(9); BinaryTreeNode nodeA4 = new BinaryTreeNode(2); BinaryTreeNode nodeA5 = new BinaryTreeNode(5); nodeA1.leftChild = nodeA2; nodeA2.leftChild = nodeA3; nodeA3.leftChild = nodeA4; nodeA4.leftChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(3); nodeB1.leftChild = nodeB2; nodeB2.leftChild = nodeB3; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), false); } // 05.樹中結點只有右子結點,樹B是樹A的子結構 // 8 8 // \ \ // 8 9 // \ \ // 9 2 // \ // 2 // \ // 5 [TestMethod] public void HasSubTreeTest5() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(9); BinaryTreeNode nodeA4 = new BinaryTreeNode(2); BinaryTreeNode nodeA5 = new BinaryTreeNode(5); nodeA1.rightChild = nodeA2; nodeA2.rightChild = nodeA3; nodeA3.rightChild = nodeA4; nodeA4.rightChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(2); nodeB1.rightChild = nodeB2; nodeB2.rightChild = nodeB3; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), true); } // 06.樹中結點只有右子結點,樹B不是樹A的子結構 // 8 8 // \ \ // 8 9 // \ / \ // 9 3 2 // \ // 2 // \ // 5 [TestMethod] public void HasSubTreeTest6() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(9); BinaryTreeNode nodeA4 = new BinaryTreeNode(2); BinaryTreeNode nodeA5 = new BinaryTreeNode(5); nodeA1.rightChild = nodeA2; nodeA2.rightChild = nodeA3; nodeA3.rightChild = nodeA4; nodeA4.rightChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(3); BinaryTreeNode nodeB4 = new BinaryTreeNode(2); nodeB1.rightChild = nodeB2; SetSubTreeNode(nodeB2, nodeB3, nodeB4); Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), false); } // 07.樹A為空樹 [TestMethod] public void HasSubTreeTest7() { BinaryTreeNode nodeB1 = new BinaryTreeNode(8); BinaryTreeNode nodeB2 = new BinaryTreeNode(9); BinaryTreeNode nodeB3 = new BinaryTreeNode(3); BinaryTreeNode nodeB4 = new BinaryTreeNode(2); nodeB1.rightChild = nodeB2; SetSubTreeNode(nodeB2, nodeB3, nodeB4); Assert.AreEqual(SubTreeHelper.HasSubTree(null, nodeB1), false); } // 08.樹B為空樹 [TestMethod] public void HasSubTreeTest8() { BinaryTreeNode nodeA1 = new BinaryTreeNode(8); BinaryTreeNode nodeA2 = new BinaryTreeNode(8); BinaryTreeNode nodeA3 = new BinaryTreeNode(9); BinaryTreeNode nodeA4 = new BinaryTreeNode(2); BinaryTreeNode nodeA5 = new BinaryTreeNode(5); nodeA1.rightChild = nodeA2; nodeA2.rightChild = nodeA3; nodeA3.rightChild = nodeA4; nodeA4.rightChild = nodeA5; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, null), false); } // 09.樹A和樹B都為空樹 [TestMethod] public void HasSubTreeTest9() { Assert.AreEqual(SubTreeHelper.HasSubTree(null, null), false); }
3.3 測試結果
(1)測試通過情況
(2)程式碼覆蓋率
作者:周旭龍
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。
相關推薦
劍指Offer面試題:17.樹的子結構
一、題目:樹的子結構 題目:輸入兩棵二叉樹A和B,判斷B是不是A的子結構。例如下圖中的兩棵二叉樹,由於A中有一部分子樹的結構和B是一樣的,因此B是A的子結構。 該二叉樹的節點定義如下,這裡使用C#語言描述: public class BinaryTreeNode {
劍指offer 面試題:重建二叉樹
題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。 思路:二叉樹先序是根左右,中序 是左根右。所以先找到
劍指Offer面試題:22.二叉搜尋樹的後序遍歷序列
一、題目:二叉搜尋樹的後序遍歷序列 題目:輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後序遍歷的結果。如果是則返回true,否則返回false。假設輸入的陣列的任意兩個數字都互不相同。 例如在下面的一顆二叉搜尋樹中,輸入陣列{5,7,6,9,11,10,8},則返回true,因為這個整數序列是
劍指Offer面試題:23.二叉樹中和為某一值的路徑
一、題目:二叉樹中和為某一值的路徑 題目:輸入一棵二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。例如輸入下圖中二叉樹和整數22,則打印出兩條路徑,第一條路徑包含結點10、12,第二條路徑包含結點10、5和7。 二叉
劍指Offer面試題:25.二叉搜尋樹與雙向連結串列
一、題目:二叉搜尋樹與雙向連結串列 題目:輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。比如輸入下圖中左邊的二叉搜尋樹,則輸出轉換之後的排序雙向連結串列。 二叉搜尋樹的節點定義如下,這裡使用C#語言描述:
劍指Offer面試題:21.從上到下列印二叉樹
一、題目:從上到下列印二叉樹 題目:從上往下打印出二叉樹的每個結點,同一層的結點按照從左到右的順序列印。例如輸入下圖中的二叉樹,則依次打印出8、6、10、5、7、9、11。 二叉樹節點的定義如下,採用C#語言描述: public class BinaryTreeNode
劍指offer面試題:求二叉樹的映象(遞迴、迴圈解法及測試用例)
題目:給定二叉樹,將其變換為源二叉樹的映象。 二叉樹的定義如下: struct TreeNode { int val; TreeNode* left; TreeNode* right; }; 輸入描述: 二叉樹的映象定義: 源二叉樹
牛客網線上程式設計專題《劍指offer-面試題18》樹的子結構
題目連結: 題目描述: 解題思路: 本題的解題過程分為兩步: 1)第一步,在樹A中查詢與根結點的值一樣的結點,這實際上就是樹的遍歷。 2)第二步,判斷A樹中以R為根結點的子樹是不是和樹B具有相同的結構。如果結點R的值和樹B的根結點不相同,則以R為根結點的子樹
劍指offer 面試題:從尾到頭列印連結串列
題目:輸入一個連結串列,按連結串列值從尾到頭的順序返回一個ArrayList。 思路:有多種放法。(1)先反轉連結串列,再列印連結串列。(2)使用棧。 /** * struct ListNode { * int val; * struct ListNode *n
劍指Offer面試題:31.兩個連結串列的第一個公共節點
一、題目:兩個連結串列的第一個公共節點 題目:輸入兩個連結串列,找出它們的第一個公共結點。 連結串列結點定義如下,這裡使用C#語言描述: public class Node { public int key; public Node
劍指Offer面試題:2.二維陣列中的查詢
一、題目:二維陣列中的查詢 題目:在一個二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。 例如下面的二維陣列就是每行、每列都遞增排序。如果在這個陣列中查詢數字7,則返回true;
劍指Offer面試題:14.連結串列的倒數第k個節點
PS:這是一道出境率極高的題目,記得去年參加校園招聘時我看到了3次,但是每次寫的都不完善。 一、題目:連結串列的倒數第k個節點 題目:輸入一個連結串列,輸出該連結串列中倒數第k個結點。為了符合大多數人的習慣,本題從1開始計數,即連結串列的尾結點是倒數第1個結點。例如一個連結串列有6個結點,從頭結點開始
劍指Offer面試題:28.連續子陣列的最大和
一、題目:連續子陣列的最大和 題目:輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或連續的多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)。例如輸入的陣列為{1,-2,3,10,-4,7,2,-5},和最大的子陣列為{3,10,-4,7,2},因此輸出為該子陣列的和18。
劍指Offer面試題:4.從尾到頭列印連結串列
一、題目:從尾到頭列印連結串列 題目:輸入一個連結串列的頭結點,從尾到頭反過來打印出每個結點的值。 到解決這個問題肯定要遍歷連結串列。遍歷的順序是從頭到尾的順序,可輸出的順序卻是從尾到頭。也就是說第一個遍歷到的結點最後一個輸出,而最後一個遍歷到的結點第一個輸出。這就是典型的“後進先出”,我
劍指Offer面試題:10.數值的整數次方
一、題目:數值的整數次方 題目:實現函式double Power(doublebase, int exponent),求base的exponent次方。不得使用庫函式,同時不需要考慮大數問題。 在.NET Framework提供的BCL中,Math類實現了一個Pow方法,例如要求2的三次方,可
劍指Offer面試題:6.用兩個棧實現佇列
一、題目:用兩個棧實現佇列 題目:用兩個棧實現一個佇列。佇列的宣告如下,請實現它的兩個函式appendTail和deleteHead,分別完成在佇列尾部插入結點和在佇列頭部刪除結點的功能。 原文是使用C++結合模板實現的定義,這裡我們採用C#結合泛型來實現這個佇列的定義,我們要實現的就是兩
劍指Offer面試題:20.棧的壓入、彈出序列
一、題目:棧的壓入、彈出序列 題目:輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否為該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1、2、3、4、5是某棧的壓棧序列,序列4、5、3、2、1是該壓棧序列對應的一個彈出序列,但4、3、5、1、2就不可能是該壓棧序列的彈出序列。
劍指Offer面試題:30.第一個只出現一次的字元
一、題目:第一個只出現一次的字元 題目:在字串中找出第一個只出現一次的字元。如輸入"abaccdeff",則輸出'b'。要求時間複雜度為O(n)。 最直觀的想法是從頭開始掃描這個字串中的每個字元。當訪問到某字元時拿這個字元和後面的每個字元相比較,如果在後面沒有發現重複的字元,則該字元就是隻出現
劍指Offer面試題:34.翻轉單詞順序VS左旋轉字串
一、題目一:翻轉單詞順序 1.1 題目說明 題目一:輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字元的順序不變。為簡單起見,標點符號和普通字母一樣處理。例如輸入字串"I am a student.",則輸出"student. a am I"。 1.2 解題思路 第一步翻轉句子中所有的字
劍指Offer面試題:11.列印1到最大的n位數
一、題目:列印1到最大的n位數 題目:輸入數字n,按順序打印出從1最大的n位十進位制數。比如輸入3,則打印出1、2、3一直到最大的3位數即999。 二、不同的解法 2.1 不假思索的解法 最容易想到的辦法是先求出最大的n位數,然後用一個迴圈從1開始逐個列印: static v