1. 程式人生 > >【LeetCode】Symmetric Tree(對稱二叉樹)

【LeetCode】Symmetric Tree(對稱二叉樹)

這道題是LeetCode裡的第101道題。是我在學資料結構——二叉樹的時候碰見的題。

題目如下:

給定一個二叉樹,檢查它是否是映象對稱的。

例如,二叉樹 [1,2,2,3,4,4,3] 是對稱的。

     1
   /   \
  2     2
 / \   / \
3   4 4   3

但是下面這個 [1,2,2,null,3,null,3] 則不是映象對稱的:

    1
   / \
  2   2
   \   \
    3   3

說明:

你可以運用遞迴和迭代兩種方法解決這個問題。

 

解題思路:

讀完題目後我首先想到的是用遍歷的方法來解題,樹的遍歷有三種:前序遍歷,中序遍歷和後序遍歷。

這裡我選擇的是中序遍歷,對根節點的左右子樹分別進行中序遍歷,但是因為要符合題目的要求——對稱,所以兩種中序遍歷的方式不一樣,根節點左子樹採用LDR中序遍歷,根節點右子樹採用RDL中序遍歷。

如同上面的兩個示例:第一顆樹根節點的左子樹遍歷結果是[3,2,4],而根節點的右子樹遍歷結果是[3,2,4],相等。對稱。

第二顆樹根節點的左子樹遍歷結果是[2,3],而根節點的右子樹遍歷結果是[3,2],不相等。不對稱。

 

程式碼如下: 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> LPreOrder(TreeNode* tree){//LDR中序遍歷
        stack<TreeNode*>st;//節點堆疊
        vector<int>res;
        TreeNode* pt;
        if(tree==NULL)return res;
        pt=tree;
        while(pt!=NULL||st.size()!=0){
            while(pt!=NULL){//先訪問左節點
                st.push(pt);
                pt=pt->left;
            }
            pt=st.top();//最下邊的左節點
            res.push_back(pt->val);//儲存數值
            st.pop();
            pt=pt->right;//訪問右節點
        }
        return res;
    }
    vector<int> RPreOrder(TreeNode* tree){//RDL中序遍歷
        stack<TreeNode*>st;
        vector<int>res;
        TreeNode* pt;
        if(tree==NULL)return res;
        pt=tree;
        while(pt!=NULL||st.size()!=0){
            while(pt!=NULL){
                st.push(pt);
                pt=pt->right;
            }
            pt=st.top();
            res.push_back(pt->val);
            st.pop();
            pt=pt->left;
        }
        return res;
    }
    bool isSymmetric(TreeNode* root) {
        if(root==NULL)//根節點是否為空
            return true;
        if(root->left==NULL||root->right==NULL){//左右子樹其中一個是否為空
            if(root->left==NULL&&root->right==NULL)//左右子樹是否為空
                return true;
            return false;
        }
        else{
            if(root->left->val!=root->right->val)return false;
            vector<int>Lorder,Rorder;
            Lorder=LPreOrder(root->left);//遍歷
            Rorder=RPreOrder(root->right);//遍歷
            if(Lorder!=Rorder)return false;//判斷遍歷結果是否相同
            return true;
        }
    }
};

測試結果通過。。。

這其實這還沒結束,因為如果是這顆樹的話(自己突然想到的):

很明顯不對稱是不是,但是仍然能通過測試,就說明在測試案例裡沒有這顆樹。鑽了個空子。

 

然後我沒辦法只好用官方解題思路:

就是使用雙節點遞迴對每一個節點及其相對稱的節點進行左右對稱判斷。類似於廣度優先演算法,或是層次遍歷。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isMirror(TreeNode* t1,TreeNode* t2){
        if(t1==NULL&&t2==NULL)return true;
        if(t1==NULL||t2==NULL)return false;
        return (t1->val==t2->val)
            &&isMirror(t1->left,t2->right)
            &&isMirror(t2->left,t1->right);
    }
    bool isSymmetric(TreeNode* root) {
        return isMirror(root,root);
    }
};

是不是看起了簡單多了?我也學習到了。

個人總結:寫演算法不能只光顧一個案例,要善於使用各種特殊的案例來測試演算法的正確性和可行性,在這裡我就是在編寫過程中沒有充分考慮到空節點的情況,導致了多次提交的錯誤。