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].
這道題給了我們一個數組,讓我們創建一個最大二叉樹,創建規則是數組中的最大值為根結點,然后分隔出的左右部分再分別創建最大二叉樹。那么明眼人一看就知道這是分治法啊,果斷上遞歸啊。首先就是要先找出數組中的最大值,由於數組是無序的,所以沒啥好的辦法,就直接遍歷吧,找到了最大值,就創建一個結點,然后將左右兩個子數組提取出來,分別調用遞歸函數並將結果連到該結點上,最后將結點返回即可,參見代碼如下:
解法一:
class Solution { public: TreeNode* constructMaximumBinaryTree(vector<int>& nums) { if (nums.empty()) return NULL; int mx = INT_MIN, mx_idx = 0; for (int i = 0; i < nums.size(); ++i) { if (mx < nums[i]) { mx = nums[i]; mx_idx = i; } } TreeNode *node = new TreeNode(mx); vector<int> leftArr = vector<int>(nums.begin(), nums.begin() + mx_idx); vector<int> rightArr = vector<int>(nums.begin() + mx_idx + 1, nums.end()); node->left = constructMaximumBinaryTree(leftArr); node->right = constructMaximumBinaryTree(rightArr); return node; } };
下面這種方法也是遞歸的解法,和上面的解法稍有不同的是不必提取子數組,而是用兩個變量來指定子數組的范圍,其他部分均和上面的解法相同,參見代碼如下:
解法二:
class Solution { public: TreeNode* constructMaximumBinaryTree(vector<int>& nums) { if (nums.empty()) return NULL; return helper(nums, 0, nums.size() - 1); } TreeNode* helper(vector<int>& nums, int left, int right) { if (left > right) return NULL; int mid = left; for (int i = left + 1; i <= right; ++i) { if (nums[i] > nums[mid]) { mid = i; } } TreeNode *node = new TreeNode(nums[mid]); node->left = helper(nums, left, mid - 1); node->right = helper(nums, mid + 1, right); return node; } };
下面這種解法是論壇上的高分解法,使用到了一個輔助數組v來讓保持降序。我們遍歷數組,對於每個遍歷到的數字,創建一個結點,然后進行循環,如果數組v不空,且末尾結點值小於當前數字,那么將末尾結點連到當前結點的左子結點,並且移除數組中的末尾結點,這樣可以保證子結點都會小於父結點。循環結束后,如果此時數組v仍不為空,說明結點值很大,那么將當前結點連到數組末尾結點的右子結點上。之后別忘了將當前結點加入數組v中,最后返回數組v的首結點即可,如果不太容易理解的話,就把題目中的例子帶入一步一步運行看一下吧,參見代碼如下:
解法三:
class Solution { public: TreeNode* constructMaximumBinaryTree(vector<int>& nums) { vector<TreeNode*> v; for (int num : nums) { TreeNode *cur = new TreeNode(num); while (!v.empty() && v.back()->val < num) { cur->left = v.back(); v.pop_back(); } if (!v.empty()) { v.back()->right = cur; } v.push_back(cur); } return v.front(); } };
參考資料:
https://discuss.leetcode.com/topic/98457/java-c-simple-recursive-method