@@ -418,103 +418,6 @@ class Solution {
418418}
419419```
420420
421- # 分治算法
422-
423- ## [ 07、重建二叉树] ( https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/ )
424-
425- 重建二叉树的关键在于中序遍历的结果:[ 左子树区间] root[ 右子树区间] ,通过中序遍历的结果可以清晰的得出根节点与左右子树之间的关系。
426-
427- 此题要求使用中序遍历与前序遍历的结果还原二叉树,从中我们可得到如下信息:
428-
429- 1 . 中序遍历的特点:[ 左子树区间] root[ 右子树区间]
430-
431- 2 . 前序遍历的特点:root [ 左子树区间] [ 右子树区间 ]
432-
433- 由于题目说明不存在重复的值,所以我们可以将中序遍历的结果与位置索引建立一个 map,通过前序遍历中的头结点即可在时间复杂度为 O(1) 的情况下从 map 中获取左右区间的边界。
434-
435- 在 map 之外我们还需要双指针来分别标记位于中序遍历中的左右子树边界;还需要一个全局变量指明当前 root 位于前序遍历的索引;根据这些值通过递归不断的压缩左右区间,最终重建二叉树。
436-
437- ``` java
438- class Solution {
439- private Map<Integer , Integer > mCache = new HashMap<> ();
440- private int mCurRootIndexOnPreorder = 0 ;
441- public TreeNode buildTree (int [] preorder , int [] inorder ) {
442- // 中序遍历是关系,需要将值和位置的关系存储起来
443- for (int i = 0 ; i < inorder. length; i++ ) {
444- mCache. put(inorder[i], i);
445- }
446-
447- return buildTree(preorder, inorder, 0 , inorder. length - 1 );
448- }
449-
450- private TreeNode buildTree (int [] preorder , int [] inorder , int start , int end ) {
451- // 边界条件
452- if (start > end) {
453- return null ;
454- }
455- // 获取头结点的值
456- int rootVal = preorder[mCurRootIndexOnPreorder++ ];
457- // 获取头结点在中序遍历的位置
458- int rootIndexOfInoder = mCache. get(rootVal);
459- TreeNode root = new TreeNode (rootVal);
460- // 递归建立左右子树
461- root. left = buildTree(preorder, inorder, start, rootIndexOfInoder - 1 );
462- root. right = buildTree(preorder, inorder, rootIndexOfInoder + 1 , end);
463- return root;
464- }
465- }
466-
467- ```
468-
469-
470-
471-
472-
473- ## [ 33、二叉搜索树的后序遍历序列] ( https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/ )
474-
475- 这道题使用单调栈可以获得最优解,而且能更好的理解。
476-
477- 首先明确什么是二叉搜索树:左节点 <根节点 < 右节点(left < root < right)即越往右数值越大,但是此题给出的是后续遍: left -> right -> root 并不满足单调性。但是我们将顺序反过来就形成了 root -> right -> left 即可以得到一个从小 -> 大 -> 小的两个严格单调区间。此时我们就可以使用单调栈来判断题目中提出的数组是否满足二叉搜索树的递增关系了。
478-
479- 一开始我们将反序后的数组逐个入栈,如果不满足单调递增性,这说明进入了 [ left 左子树区间] 。此时要做的是找到当前值(左子树值)所对应的根节点。怎么做呢?拿栈顶元素与当前值进行比较,直到把比当前值大的数全部出栈为止,最后一个出栈的就是当前值对应的根节点。
480-
481- 这里要注意的是 root > left 这个关系,如果当前值小于了 [ left 左子树区间] 的值,则返回 false。
482-
483-
484-
485- 就这样一路比下去,如果所有的左子树值都小于所对应的 root 则满足二叉搜索树特点,否则就不是。
486-
487- ``` java
488- class Solution {
489- public boolean verifyPostorder (int [] postorder ) {
490- // 判定边界条件
491- if (postorder == null || postorder. length == 0 ) {
492- return true ;
493- }
494- final Stack<Integer > stack = new Stack<> ();
495- // 简化判断左子树与 root 关系的判定逻辑
496- int root = Integer . MAX_VALUE ;
497- // 将数组反过来得到单调关系
498- for (int i = postorder. length - 1 ; i >= 0 ; i-- ) {
499- // 左子树大于了 root, 不满足二叉搜索树特性
500- if (postorder[i] > root) {
501- return false ;
502- }
503- // 不满足单调性,说明进入了左子树区间,开始寻找当前左子树对应的 root
504- while (! stack. isEmpty() && postorder[i] < stack. peek()) {
505- root = stack. pop();
506- }
507- stack. push(postorder[i]);
508- }
509- return true ;
510- }
511- }
512- ```
513-
514- # [ 17、打印从 1 到最大的 n 位数] ( https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/ )
515-
516-
517-
518421# 分治算法
519422
520423## [ 07. 重建二叉树] ( https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/99lxci/ )
@@ -633,7 +536,7 @@ class Solution {
633536
634537
635538
636- ## 解法1:递推,时间复杂度 O(logn)、空间复杂度O(1)
539+ ### 解法1:递推,时间复杂度 O(logn)、空间复杂度O(1)
637540
638541``` java
639542class Solution {
@@ -675,7 +578,7 @@ class Solution {
675578}
676579```
677580
678- ## 解法2: 递归,时间复杂度 O(logn)、空间复杂度O(n)
581+ ### 解法2: 递归,时间复杂度 O(logn)、空间复杂度O(n)
679582
680583``` java
681584class Solution {
@@ -846,3 +749,46 @@ class Solution {
846749}
847750```
848751
752+ ## [ 33、二叉搜索树的后序遍历序列] ( https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/ )
753+
754+ 这道题使用单调栈可以获得最优解,而且能更好的理解。
755+
756+ 首先明确什么是二叉搜索树:左节点 <根节点 < 右节点(left < root < right)即越往右数值越大,但是此题给出的是后续遍: left -> right -> root 并不满足单调性。但是我们将顺序反过来就形成了 root -> right -> left 即可以得到一个从小 -> 大 -> 小的两个严格单调区间。此时我们就可以使用单调栈来判断题目中提出的数组是否满足二叉搜索树的递增关系了。
757+
758+ 一开始我们将反序后的数组逐个入栈,如果不满足单调递增性,这说明进入了 [ left 左子树区间] 。此时要做的是找到当前值(左子树值)所对应的根节点。怎么做呢?拿栈顶元素与当前值进行比较,直到把比当前值大的数全部出栈为止,最后一个出栈的就是当前值对应的根节点。
759+
760+ 这里要注意的是 root > left 这个关系,如果当前值小于了 [ left 左子树区间] 的值,则返回 false。
761+
762+
763+
764+ 就这样一路比下去,如果所有的左子树值都小于所对应的 root 则满足二叉搜索树特点,否则就不是。
765+
766+ ``` java
767+ class Solution {
768+ public boolean verifyPostorder (int [] postorder ) {
769+ // 判定边界条件
770+ if (postorder == null || postorder. length == 0 ) {
771+ return true ;
772+ }
773+ final Stack<Integer > stack = new Stack<> ();
774+ // 简化判断左子树与 root 关系的判定逻辑
775+ int root = Integer . MAX_VALUE ;
776+ // 将数组反过来得到单调关系
777+ for (int i = postorder. length - 1 ; i >= 0 ; i-- ) {
778+ // 左子树大于了 root, 不满足二叉搜索树特性
779+ if (postorder[i] > root) {
780+ return false ;
781+ }
782+ // 不满足单调性,说明进入了左子树区间,开始寻找当前左子树对应的 root
783+ while (! stack. isEmpty() && postorder[i] < stack. peek()) {
784+ root = stack. pop();
785+ }
786+ stack. push(postorder[i]);
787+ }
788+ return true ;
789+ }
790+ }
791+ ```
792+
793+ ## [ 17、打印从 1 到最大的 n 位数] ( https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/ )
794+
0 commit comments