1. 程式人生 > >[LeetCode] 654. Maximum Binary Tree

[LeetCode] 654. Maximum Binary Tree

output 時間 tarray 代碼 arrays 是我 函數 內部 程序

Given an integer array with no duplicates. A maximum tree building on this array is defined as follow:

The root is the maximum number in the array.
The left subtree is the maximum tree constructed from left part subarray divided by the maximum number.
The right subtree is the maximum tree constructed from right part subarray divided by the maximum number.
Construct the maximum tree by the given array and output the root node of this tree.

Example 1:

Input: [3,2,1,6,0,5]
Output: return the tree root node representing the following tree:

     6
   /     3     5
   \    / 
    2  0   
             1

Note:
The size of the given array will be in the range [1,1000].


題目不算難,可以很容易的想到解決思路:

  1. 創建一個根節點,其值為數組的最大值
  2. 創建根節點的左節點,左節點的值為數組左半部分的最大值
  3. 創建根節點的右節點,右節點的值為數組右半部分的最大值
  4. 遞歸以上操作

於是我用最直接的代碼寫出了以下解決方法

Solution:

   class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) {
        val = x;
    }
   }
   public class Solution {
    public static TreeNode constructMaximumBinaryTree(int[] nums) {
        if(nums.length==0) return null;
        int
max=getMaxNumber(nums); TreeNode root=new TreeNode(max); root.left=constructMaximumBinaryTree(getArrayLeftPart(max, nums)); root.right=constructMaximumBinaryTree(getArrayRightPart(max, nums)); return root; } public static int getMaxNumber(int[] nums) { int[] tempArray = nums.clone(); Arrays.sort(tempArray); return tempArray[tempArray.length - 1]; } public static int[] getArrayLeftPart(int spilt, int[] nums) { List<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < nums.length; i++) { if (nums[i] == spilt) { break; } list.add(nums[i]); } int[] result = new int[list.size()]; for (int k = 0; k < list.size(); k++) { result[k] = list.get(k); } return result; } public static int[] getArrayRightPart(int spilt, int[] nums) { List<Integer> list = new ArrayList<Integer>(); for (int i = nums.length - 1; i > 0; i--) { if (nums[i] == spilt) { break; } list.add(nums[i]); } int[] result = new int[list.size()]; for (int k = list.size() - 1; k >= 0; k--) { result[list.size() - k - 1] = list.get(k); } return result; } }

這個解法給了AC,但是效率很低,Leetcode給出的運行時間是433ms。對於性能差我能想到的原因有:

  1. 頻繁的創建數組,獲取數組最大值需要克隆數組,獲取數組的左半部分也需要從list轉為數組,這些都會影響程序的性能。
  2. 頻繁遍歷數組,這個不用我多說,看代碼就可以。

性能優化

上面的方法使用在遞歸時傳的是值(value),這樣的遞歸需要傳遞的參數個數比較少,但對資源的利用率不高。所以我們改為傳遞索引(index)的方式,提高對數組的利用率。這樣在數據傳遞的時候只需要傳遞數組的索引值,整個遞歸過程只需要對一個數組進行操作。

    public static TreeNode constructMaximumBinaryTree(int[] nums){
         return constructor(nums,0,nums.length-1);
     }
     //給出的method只能傳遞一個參數,所以用一個新的method
     public static TreeNode constructor(int[] nums,int left,int right){
         if (left>right)
             return null;
         int max=MaxArrayIndex(nums, left, right);
         TreeNode root=new TreeNode(nums[max]);
         root.left=constructor(nums,left,max-1);
         root.right=constructor(nums, max+1, right);
         return root;
     }
     //獲取數組中最大值的索引
     public static int MaxArrayIndex(int[] nums,int left,int right){
         int point=nums[left];
         int max_index=left;
         for(int i=left+1;i<=right;i++){
             if(nums[i]>point){
                 point=nums[i];
                 max_index=i;
             }else continue;
         }
         return max_index;
     }

改進後運行時間降到了13ms,超過了66.8%的提交。

邊界問題

邊界問題似乎不是什麽大問題,但它卻會在一定程度上阻礙你解題的速度。

首先我們得先了解哪裏會出現數組越界的情況。容易想到越界肯定容易在索引發生變化的地方出現,也就是在遞歸那一步的時候。由於在遞歸時我們改變了數組的索引,所以我們必須在函數的第一步判斷索引是不是有效的。在本例中你需要保證:

  1. MaxArrayIndex 函數的索引保持的合法範圍內。
  2. constructMaximumBinaryTree 的參數保持在合法範圍內,本例中顯然沒有問題。
  3. 遞歸函數constructor 中合理的索引校驗

第一點保證了遞歸內部獲取的索引一定是合法的。第二點保證了,調用遞歸時索引的值是合法的。第三點保證了子遞歸出現索引問題時能夠及時阻斷這個子遞歸。

[LeetCode] 654. Maximum Binary Tree