輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

要求分析:

1、第一次判斷時,如果B爲空,則返回空
2、先判斷B根節點的值,如果B根節點的與A的根節點值相同,則判斷A的左子樹和B的左子樹及A的右子樹和B的右子樹是爲子結構關係。(遞歸)
3、直到判斷到B的節點值與A的節點值相等,而B沒有子樹,則此時爲其子結構
4、如果判斷過程中,B樹的前面部分都爲A樹從節點root1Now開始的一部分,但是最後出現了值不相等,或者B還有子樹而A沒有子樹的情況,則A應該返回至root1Now的左右節點,B應該返回值最初的B。

代碼

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    TreeNode root1Now=new TreeNode(0);
    TreeNode root2Root=new TreeNode(0);
    boolean newStart=true;
    boolean begin=true;
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(begin==true)
        {
            if(root2==null)
            {
                return false;
            }
            else
            {
                begin=false;
                return HasSubtree(root1,root2);
            }
        }
        else
        {
            if(root2==null)
                return true;
            else
            {
                if(root1==null)
                    return false;
                if(root1.val==root2.val)
                {
                    if(newStart ==true) 
                    {
                        root1Now=root1;
                        root2Root=root2;
                    }
                    newStart=false;
                    if(HasSubtree(root1.right,root2.right)&&HasSubtree(root1.left,root2.left))/*子樹之間要都是對應的子節點*/
                        return true;
                    else
                    {
                        newStart=true;
                        root1=root1Now;
                        root2=root2Root;
                        return (HasSubtree(root1.right,root2)||HasSubtree(root1.left,root2));
                    }
                }
                else
                {
                    if(newStart==false)/*判斷是否開始了一次左右子樹是否子結構的判斷,如果開始了是否爲左右
                    子結構的判斷,但是又出現了不相等的情況,則應該直接返回false,然後從之前記錄的位置重新
                    開始*/
                    {
                        return false;
                    }else return (HasSubtree(root1.right,root2)||HasSubtree(root1.left,root2));
                }
            }
        }
    }
}

注意事項(這裏記錄了我寫代碼時出現的bug,看懂以上代碼的可以忽略)

關於遞歸的問題

關於遞歸有不同的調用情況
1、

return (HasSubtree(root1.right,root2)||HasSubtree(root1.left,root2));

這種是這個節點和root2的根節點值不相同,所以應該在root1的左右子樹中繼續找。
2、

if(HasSubtree(root1.right,root2.right)&&HasSubtree(root1.left,root2.left))/*子樹之間要都是對應的子節點*/
                        return true;

這種情況是必須兩者都是子結構,才能返回true。
但是在再次調用

HasSubtree(root1.right,root2.right)

這個函數的時候,複用了一段關於節點值不相等的時候應該的操作,那這個就應該分兩種情況。
1、如果是在newStart的過程中,就是根節點相等,要判斷子樹的時候。出現了值不相等,則應該直接返回false,這樣HasSubtree(root1.right,root2.right)的查找就會結束,就會退到之前開始的地方。
2、如果不是在newStart的過程中,就是一直在往下找一個相等的節點的時候,則就是直接往下尋找。

我的錯誤

我在第一種情況的時候,沒有返回。而是直接回到了開始的地方,開始新的查找。
但是這時候,他還是屬於

HasSubtree(root1.right,root2.right)&&HasSubtree(root1.left,root2.left)

這個過程中,也就是說,如果是這樣,newStart的值會產生混亂。
root1=root1Now;
root2=root2Root;
的過程沒有辦法得到保證正確。

一次低級錯誤

begin是表示這是第一次執行該函數的標誌,用於實現B一開始就是null時,直接返回false。
正確的代碼如下:

if(begin==true)
        {
            if(root2==null)
            {
                return false;
            }
            else
            {
                begin=false;
                return HasSubtree(root1,root2);
            }
        }

我寫了一次錯誤代碼爲:

if(begin==true)
        {
            if(root2==null)
            {
                return false;
            }
         }
         ......
         return false   /*這裏*/

後面的沒變,但是提示說,缺一個返回,我就在最後隨便寫了個返回 return false ???
我也不知道我在想什麼哦。實際這種問題就是提醒,在裏面這個if裏面,少了一種情況沒有說明。
這裏的情況是沒有變化begin。這樣子直接就是返回false了。這個是基礎錯誤。

參考鏈接
https://www.nowcoder.com/profile/562667/codeBookDetail?submissionId=1523155

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章