diff --git "a/pics/654\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.png" "b/pics/654\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.png" new file mode 100644 index 0000000000..91f985bf55 Binary files /dev/null and "b/pics/654\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.png" differ diff --git "a/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md" "b/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md" index fed9b2b991..f45adb0a4d 100644 --- "a/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md" +++ "b/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md" @@ -212,6 +212,96 @@ root->right = traversal(nums, maxValueIndex + 1, right); 第二版相应的终止条件,是遇到空节点,也就是数组区间为0,就终止了。 +### 非递归方法 + +将原数组转化为二叉树时,使数字飘起来,可以想象:越大的数字飘得越高(越接近根节点)。 + +如原题 【3,2,1,6,0,5】: + +image-20250216223034714 + +以 **从左到右遍历数组** 的方式构造最大二叉树,避免了递归方法带来的额外栈空间消耗,时间效能上也优一些。 + +1. 首先创建一个存放各个节点的地址的vector, 可以先把各个节点创建出来,也可以在遍历的过程中创建。 + +2. 遍历 `nums` 逐步构造树 + +```cpp +for (int i = 1; i < nums.size(); i++) { + TreeNode* t = new TreeNode(nums[i]); + arr.push_back(t); +``` + +- 依次读取 `nums[i]` 并新建 `TreeNode`,同时存入 `arr` 数组。 + +3. **找到 `nums[i]` 前面第一个比它大的数`nump[j]`,则 i 对应的节点应该是 j 节点的右子树,并把 j 原来的右子树(在数组的位置是 i 左边)放在 i 的左子树上。** + +```cpp +int j = i - 1; +for (; j >= 0; j--) { + if (nums[j] > nums[i]) { + TreeNode* l = arr[j]->right; + arr[j]->right = t; + t->left = l; + break; + } +} +``` + +- 从 `nums[i]` **向左遍历**,找到 **第一个比 `nums[i]` 大的数 `nums[j]`**。 +- 构造父子关系: + - `nums[i]` 作为 `nums[j]` 的**右子节点**。 + - 若 `nums[j]` 原本已有右子树 `l`,则 `l` 作为 `nums[i]` 的**左子节点**。 + +4. .处理 `nums[i]` 是当前最大值的情况 + +```cpp +if (j == -1) { + t->left = root; + root = t; +} +``` + +- 如果 `nums[i]` 比前面所有数都大,则为新的根节点: + - 设 `t->left = root`,即将 `root` 作为 `t` 的左子树。 + - 更新 `root = t`,因为 `nums[i]` 是当前最大值,必须作为新的根节点。 + +代码如下: + +```cpp +class Solution { + public: + TreeNode* constructMaximumBinaryTree(vector& nums) { + // new一个根节点 + TreeNode* root = new TreeNode(nums[0]); + // 创建一个存放各个node地址的数组,方便修改,与nums顺序一致 + vector arr; + // 先把第一个节点设为根节点,放入数组 + arr.push_back(root); + for(int i = 1; i < nums.size(); i++) { + TreeNode* t = new TreeNode(nums[i]); + arr.push_back(t); + int j = i-1; + for(; j >= 0; j--) { + /* 找到前面第一个大于该数的已有节点 */ + if(nums[j] > nums[i]){ + TreeNode* l = arr[j]->right; + arr[j]->right = t; + t->left = l; + break; + } + } + if(j == -1){ + /* 若没有更大的,说明这个数是目前最大的,设为根节点 */ + t->left = root; + root = t; + } + } + return root; + } + }; +``` + ## 总结