Leetcode 題解系列 -- 對稱二叉樹(遞迴)

安歌發表於2022-02-02

本專題旨在分享刷Leecode過程發現的一些思路有趣或者有價值的題目。【當然是基於js進行解答】。

遞迴演算法一直是leetcode 中等難度習題的重點型別之一,所以關鍵性不言而喻。

題目相關

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

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

    1
   / \
  2   2
   \   \
   3    3

Tips

考慮某些同學可能比較少用js來刷leetcode,我們在這裡簡單介紹下,關於樹型別的資料輸入,在js裡的表示。 形如上題中的內容,給定二叉樹的輸入,其實並非一個陣列,而應該是如下所示: 每個節點是一個object:

 const root = {
      val: 3,
      left: { // left表示當前節點的左側子節點
        val: 9,
        left: null, // 對照上圖可以看到 節點9沒有左右子節點
        right: null,
      },
      right: {
        val: 20,
        left: {
          val: 15, // 對照上圖可以看到 節點15沒有左右子節點
          left: null, 
          right: null,
        }, 
        right: {
          val: 7, // 對照上圖可以看到 節點7沒有左右子節點
          left: null, 
          right: null,
        },
      }
    }

思路解析

首先這道題是明顯的遞迴類題目, 而遞迴類的題目一般就是以下幾個步驟:

  1. 提取遞迴部分的邏輯
  2. 判斷邊界條件

image.png

  • 首先整體的邏輯上, 要判定一棵樹是映象二叉樹的話,肯定是要從根節點的左右節點開始進行對比,在遍歷過程遇到的每一組節點(用L和R表示),都要滿足L的左節點 = R的右節點 且 L的右節點 = R的左節點 由於會遞迴比較,所以這裡相等其實就只要是val值相等:
    image.png
  • 其次是考慮邊界條件

    1. 如果初始是一顆空的樹,那直接返回結果,也算對稱;
    2. 同步比對時,在任意一步,只要出現不滿足L的左節點 = R的右節點 且 L的右節點,= R的左節點 ,則提前結束,返回false;
    3. 如果能夠比對到兩邊同時結束,那麼說明是對稱樹,返回true;

那麼按照前文說的,先寫出遞迴部分的邏輯:

    var recuCompare = function (L, R) {
        if(!L && !R) { // 說明同時比對同時結束 或者是兩邊均無該子節點
            return true;
        }
        if(!L || !R || L.val !== R.val ) { // 扣除第一種情況 那麼!L 或者 !R說明左右不同時結束,也就是出現不對稱
            return false;
        }
        return recuCompare(L.left, R.right) && recuCompare(L.right, R.left); // 繼續往下比對
    }

那麼補上遞迴起始條件部分,完整程式碼就可以得出了。

完整程式碼

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isSymmetric = function(root) {
    if(!root) {return true};
    return recuCompare(root.left, root.right)
};
var recuCompare = function (L, R) {
    if(!L && !R) {
        return true;
    }
    if(!L || !R || L.val !== R.val )  {
        return false;
    }
    return recuCompare(L.left, R.right) && recuCompare(L.right, R.left);
}

有沒有發現,遞迴類題目最後都是程式碼寫出來後不長,但是理解比較吃力,所以更需要自己嘗試著去抓邏輯重點。

很建議大家在看完之後,自己手寫一次程式碼跑跑看
很建議大家在看完之後,自己手寫一次程式碼跑跑看
很建議大家在看完之後,自己手寫一次程式碼跑跑看

因為很多邊界條件的寫法和細節,其實才是除錯過程中最經常出bug的。

另外,大家可以利用本題的思路,去試著解一下 這道遞迴回溯的題目--樹的子結構 從而鞏固所學 https://leetcode-cn.com/probl...

那麼,簡簡單單一道題又搞定了!

image.png

相關文章