1. 程式人生 > 實用技巧 >二叉樹遞迴解題

二叉樹遞迴解題

83.刪除排序中的重複元素

難度 簡單

給定一個排序連結串列,刪除所有重複的元素,使得每個元素只出現一次。

示例1:

  輸入: 1->1->2
  輸出: 1->2

示例2:

  輸入: 1->1->2->3->3
  輸出: 1->2->3

Solution

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null || head.next == null)
            return head;
        head.next = deleteDuplicates(head.next);
        if (head.val == head.next.val)
            head = head.next;
        return head;
    }
}

101.對稱二叉樹

難度 簡單

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

示例1:

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

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

示例2:

  [1,2,2,null,3,null,3] 則不是映象對稱的:

      1
     / \
    2   2
     \   \
     3    3

解題思路

  遞迴問題解決步驟:
  1. 找整個遞迴的終止條件:遞迴應該在什麼時候結束?
  2. 找到返回值:應該給上一級返回什麼資訊?
  3. 本級遞迴應該做什麼:在這一級遞迴中,應該完成什麼任務?
  [參考部落格](https://lyl0724.github.io/2020/01/25/1/)

在這個題目中,目的是檢查給定的二叉樹是否映象對稱,套用遞迴解題步驟:


1. 找終止條件。樹為空的時候遞迴結束。


2. 找返回值。此題是判斷給定的二叉樹是否映象對稱,因此返回true或者false。


3. 本級遞迴應該做什麼。給定的函式isSymmetric()的傳參只有一個root,而判斷二叉樹是否映象,根節點root的左節點left和右節點right的值要相等,而且左節點left的左節點要等於右節點right的右節點,同時左節點left的右節點要等於右節點的左節點(此處的相等為val相等)。另寫一個函式,傳入左節點left和右節點right,判斷是否映象。

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null)
            return true;
        return helper(root.left, root.right);
    }

    public boolean helper(TreeNode left, TreeNode right){
        if (left == null && right == null)
            return true;
        if (left == null || right == null)
            return false;
        if (left.val == right.val)
            return helper(left.left, right.right)
                && helper(left.right, right.left);
        return false;
    }
}

110.平衡二叉樹

難度 簡單

給定一個二叉樹,判斷它是否是高度平衡的二叉樹。

本題中,一棵高度平衡二叉樹定義為:

一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過1。

示例1:

  給定二叉樹 [3,9,20,null,null,15,7]

      3
     / \
    9  20
      /  \
     15   7
  返回 true 

示例2:

  給定二叉樹 [1,2,2,3,3,null,null,4,4]

         1
        / \
       2   2
      / \
     3   3
    / \
   4   4
  返回 false 

解題思路

helper返回-1或者是平衡樹的高度,即如果是平衡樹,則返回值》=0。
helper函式中進行遞迴:
 1. 邊界條件:root == null
 2. 計算左子樹的高度
 3. 計算右子樹的高度
 4. 判斷是否為平衡樹
   是:
     返回高度值
   不是:
     返回-1

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        return helper(root) >= 0;
    }
    public int helper(TreeNode root){
        if (root == null)
            return 0;
        int leftDepth = helper(root.left);
        int rightDepth = helper(root.right);
        if (leftDepth >=0 && rightDepth >= 0 && Math.abs(leftDepth - rightDepth) <= 1)
            return Math.max(leftDepth, rightDepth) + 1;
        else 
            return -1; 
    }
}

226.翻轉二叉樹

難度 簡單

翻轉一棵二叉樹。

示例:

  輸入:
       4
     /   \
    2     7
   / \   / \
  1   3 6   9

  輸出:
       4
     /   \
    7     2
   / \   / \
  9   6 3   1

解題思路:

乍一看,感覺和映象二叉樹十分相似,只是將判斷節點值是否相等變成交換值。但是進一步思考後,其實不用這麼複雜,每個節點依次遞迴,在本級遞迴中只需要將左右節點互換就OK。

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null)
            return null;
        if (root.left == null && root.right == null)
            return root;
        if (root.left != null && root.right == null){
            root.right = root.left;
            root.left = null;
        }else if(root.left == null && root.right != null){
            root.left = root.right;
            root.right = null;
        }else{
            TreeNode temp = root.left;
            root.left = root.right;
            root.right = temp;
        }
        root.left = invertTree(root.left);
        root.right = invertTree(root.right);
        return root;   
    }
}

654.最大二叉樹

難度 中等

給定一個不含重複元素的整數陣列。一個以此陣列構建的最大二叉樹定義如下:

二叉樹的根是陣列中的最大元素。
左子樹是通過陣列中最大值左邊部分構造出的最大二叉樹。
右子樹是通過陣列中最大值右邊部分構造出的最大二叉樹。
通過給定的陣列構建最大二叉樹,並且輸出這個樹的根節點。

示例:

  輸入:[3,2,1,6,0,5]
  輸出:返回下面這棵樹的根節點:
  
        6
      /   \
     3     5
      \    / 
       2  0   
         \
          1

解題思路:

第一次提交的程式碼超出了記憶體限制,可能是因為遞迴傳參是陣列,每次複製原陣列的切片。參考大佬的程式碼後,其實只需要陣列nums,左起始位left和終點位right,遞迴邊界是left > right,觀察程式碼其本質為前序遍歷:先完成本級的任務,左節點進行遞迴,右節點再進行遞迴,結束返回結果,完成。

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return maxTree(nums, 0, nums.length - 1);
    }
        
    public TreeNode maxTree(int[] nums, int l, int r){
        if (l > r)
            return null;
        int max = findMax(nums, l, r);
        TreeNode root = new TreeNode(nums[max]);
        root.left = maxTree(nums, l, max-1);
        root.right = maxTree(nums, max+1, r);
        return root;
    }

    public int findMax(int[] nums, int l, int r){
        int max = Integer.MIN_VALUE, maxIndex = l;
        for (int i = l; i <= r; i++){
            if (max < nums[i]){
                max = nums[i];
                maxIndex = i;
            }
        }
        return maxIndex;
    }
}

938.二叉搜尋樹的範圍和

難度 簡單

給定二叉搜尋樹的根結點 root,返回 L 和 R(含)之間的所有結點的值的和。

二叉搜尋樹保證具有唯一的值。

示例1:

  輸入:root = [10,5,15,3,7,null,18], L = 7, R = 15
  輸出:32

示例2:

  輸入:root = [10,5,15,3,7,13,18,1,null,6], L = 6, R = 10
  輸出:23

解題思路:

二叉搜尋樹的特點:左子樹所有的值都比節點的值小,而右子樹所有的值都比其大。

  1. 遞迴邊界:root == null
  2. 本級任務:先判斷節點的值處於哪個範圍
      1)小於L:去右子樹找
      2)處於尋找範圍:進行加法
      3)大於R:去左子樹找
  3. 返回值:節點值 + 左邊的值 + 右邊的值

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int rangeSumBST(TreeNode root, int L, int R) {
        if (root == null)
            return 0;
        if (root.val >= L && root.val <= R)
            return root.val + rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R);
        else if (root.val < L)
            return rangeSumBST(root.right, L, R);
        else
            return rangeSumBST(root.left, L, R);
        
    }
}

劍指Offer 54.二叉搜尋樹的第k大節點

難度 簡單

給定一棵二叉搜尋樹,請找出其中第k大的節點。

示例1:

  輸入: root = [3,1,4,null,2], k = 1
     3
    / \
   1   4
    \
     2
  輸出: 4

示例2:

  輸入: root = [5,3,6,2,4,null,null,1], k = 3
         5
        / \
       3   6
      / \
     2   4
    /
   1
  輸出: 4  

解題思路:

需要全域性變數記錄ans和count,本質時中序遍歷

  1. 遞迴邊界:++count == k
  2. 本級任務:判斷count是否等於k,滿足條件直接返回退出。

Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int ans = 0, count = 0;

    public int kthLargest(TreeNode root, int k) {
        
        helper(root, k);
        return ans;
    }
    public void helper(TreeNode root, int k){
        if (root.right != null)
            helper(root.right, k);
        if (++count == k){
            ans = root.val;
            return;
        }
        if (root.left != null)
            helper(root.left, k);
    }
}