每日一練(16):對稱的二叉樹

加班猿發表於2022-02-11

title: 每日一練(16):對稱的二叉樹

categories:[劍指offer]

tags:[每日一練]

date: 2022/02/11


每日一練(16):對稱二叉樹

請實現一個函式,用來判斷一棵二叉樹是不是對稱的。如果一棵二叉樹和它的映象一樣,那麼它是對稱的。

例如,二叉樹 [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

示例 1:

輸入:root = [1,2,2,3,4,4,3]

輸出:true

示例 2:

輸入:root = [1,2,2,null,3,null,3]

輸出:false

限制:

0 <= 節點個數 <= 1000

來源:力扣(LeetCode)

連結:https://leetcode-cn.com/probl...

方法出處: 程式碼隨想錄

方法一:遞迴

遞迴三部曲

  1. 確定遞迴函式的引數和返回值

因為我們要比較的是根節點的兩個子樹是否是相互翻轉的,進而判斷這個樹是不是對稱樹,所以要比較的是兩個樹,引數自然也是左子樹節點和右子樹節點。

返回值自然是bool型別。

程式碼:

bool compare(TreeNode *left, TreeNode *right)
  1. 確定終止條件

要比較兩個節點數值相不相同,首先要把兩個節點為空的情況弄清楚!否則後面比較數值的時候就會操作空指標了。

節點為空的情況有:

  • 左節點為空,右節點不為空,不對稱,return false
  • 左不為空,右為空,不對稱 return false
  • 左右都為空,對稱,返回true

此時已經排除掉了節點為空的情況,那麼剩下的就是左右節點不為空:

  • 左右都不為空,比較節點數值,不相同就return false

此時左右節點不為空,且數值也不相同的情況我們也處理了。

程式碼:

if (left == NULL && right != NULL) {
    return false;
}
else if (left != NULL && right == NULL) {
    return false;
}
else if (left == NULL && right == NULL) {
    return true; 
}
else if (left->val != right->val) {
    return false; 
}
  1. 確定單層遞迴的邏輯

此時才進入單層遞迴的邏輯,單層遞迴的邏輯就是處理 右節點都不為空,且數值相同的情況。

  • 比較二叉樹外側是否對稱:傳入的是左節點的左孩子,右節點的右孩子。
  • 比較內測是否對稱,傳入左節點的右孩子,右節點的左孩子。
  • 如果左右都對稱就返回true ,有一側不對稱就返回false 。

程式碼:

bool outside = compare(left->left, right->right);   // 左子樹:左、 右子樹:右
bool inside = compare(left->right, right->left);    // 左子樹:右、 右子樹:左
bool isSame = outside && inside;                    // 左子樹:中、 右子樹:中(邏輯處理)
return isSame;

最終整體C++程式碼:

//1
bool compare(TreeNode* left, TreeNode* right) {
    // 首先排除空節點的情況
    if (left == NULL && right != NULL) {
        return false;
    }
    else if (left != NULL && right == NULL) {
        return false;
    }
    else if (left == NULL && right == NULL) {
        return true;
    }
    // 排除了空節點,再排除數值不相同的情況
    else if (left->val != right->val) {
        return false;
    }

    // 此時就是:左右節點都不為空,且數值相同的情況
    // 此時才做遞迴,做下一層的判斷
    bool outside = compare(left->left, right->right);   // 左子樹:左、 右子樹:右
    bool inside = compare(left->right, right->left);    // 左子樹:右、 右子樹:左
    bool isSame = outside && inside;                    // 左子樹:中、 右子樹:中 (邏輯處理)
    return isSame;
}
bool isSymmetric(TreeNode* root) {
    if (root == NULL) {
        return true;
    }
    return compare(root->left, root->right);
}

//2
bool compare(TreeNode* left, TreeNode* right) {
    if (left == NULL && right != NULL) {
        return false;
    }
    else if (left != NULL && right == NULL) {
        return false;
    }
    else if (left == NULL && right == NULL) {
        return true;
    }
    else if (left->val != right->val) {
        return false;
    } else {
        return compare(left->left, right->right) && compare(left->right, right->left);
    }
}
bool isSymmetric(TreeNode* root) {
    if (root == NULL) {
        return true;
    }
    return compare(root->left, root->right);
}

方法二:迭代(棧/佇列)

使用佇列來比較兩個樹(根節點的左右子樹)是否相互翻轉,邏輯和遞迴是一樣的

判斷根節點的左子樹和右子樹的內側和外側是否相等

// 迭代
// 佇列
bool isSymmetric(TreeNode* root) {
    if (root == NULL) {
        return true;
    }
    queue<TreeNode*> que;
    que.push(root->left);   // 將左子樹頭結點加入佇列
    que.push(root->right);  // 將右子樹頭結點加入佇列
    while (!que.empty()) {  // 接下來就要判斷這這兩個樹是否相互翻轉
        TreeNode* leftNode = que.front(); que.pop();    
        TreeNode* rightNode = que.front(); que.pop();
        if (!leftNode && !rightNode) {  // 左節點為空、右節點為空,此時說明是對稱的
            continue;
        }

        // 左右一個節點不為空,或者都不為空但數值不相同,返回false
        if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) { 
            return false;
        }
        que.push(leftNode->left);   // 加入左節點左孩子
        que.push(rightNode->right); // 加入右節點右孩子
        que.push(leftNode->right);  // 加入左節點右孩子
        que.push(rightNode->left);  // 加入右節點左孩子
    }
    return true;
}
// 棧
bool isSymmetric(TreeNode* root) {
    if (root == NULL) {
        return true;
    }
    stack<TreeNode*> st; // 這裡改成了棧
    st.push(root->left);
    st.push(root->right);
    while (!st.empty()) {
        TreeNode* leftNode = st.top(); st.pop();
        TreeNode* rightNode = st.top(); st.pop();
        if (!leftNode && !rightNode) {
            continue;
        }
        if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
            return false;
        }
        st.push(leftNode->left);
        st.push(rightNode->right);
        st.push(leftNode->right);
        st.push(rightNode->left);
    }
    return true;
}

相關文章