diff --git a/README.md b/README.md index efb19dc3..6d92a5d5 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,8 @@ * [二叉树:搜索树的公共祖先问题](https://mp.weixin.qq.com/s/Ja9dVw2QhBcg_vV-1fkiCg) * [二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA) * [二叉树:搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw) + * [二叉树:修剪一棵搜索树](https://mp.weixin.qq.com/s/QzmGfYUMUWGkbRj7-ozHoQ) + * [二叉树:构造一棵搜索树](https://mp.weixin.qq.com/s/sy3ygnouaZVJs8lhFgl9mw) @@ -163,6 +165,7 @@ * 循环不变量原则 * [0035.搜索插入位置](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q) * [0059.螺旋矩阵II](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg) + * [106.从中序与后序遍历序列构造二叉树&105. 从前序与中序遍历序列构造二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) * 字符串经典题目 * [0344.反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA) @@ -205,19 +208,46 @@ * [0144.二叉树的前序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0144.二叉树的前序遍历.md) * [0094.二叉树的中序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0094.二叉树的中序遍历.md) * [0145.二叉树的后序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0145.二叉树的后序遍历.md) + * [0589.N叉树的前序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0589.N叉树的前序遍历.md) + * [0590.N叉树的后序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0590.N叉树的后序遍历.md) + + * [0102.二叉树的层序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md) + * [0107.二叉树的层次遍历II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0107.二叉树的层次遍历II.md) + * [0199.二叉树的右视图](https://github.com/youngyangyang04/leetcode/blob/master/problems/0199.二叉树的右视图.md) + * [0637.二叉树的层平均值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0637.二叉树的层平均值.md) + * [0226.翻转二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0226.翻转二叉树.md) * [0101.对称二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0101.对称二叉树.md) + * [0100.相同的树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0100.相同的树.md) + + * [0572.另一个树的子树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0572.另一个树的子树.md) + * [0110.平衡二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0110.平衡二叉树.md) * [0104.二叉树的最大深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0104.二叉树的最大深度.md) * [0111.二叉树的最小深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0111.二叉树的最小深度.md) * [0222.完全二叉树的节点个数](https://github.com/youngyangyang04/leetcode/blob/master/problems/0222.完全二叉树的节点个数.md) + * [0404.左叶子之和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0404.左叶子之和.md) + * [0513.找树左下角的值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0513.找树左下角的值.md) + * [0112.路径总和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0112.路径总和.md) + * [0113.路径总和II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0113.路径总和II.md) + * [0257.二叉树的所有路径](https://github.com/youngyangyang04/leetcode/blob/master/problems/0257.二叉树的所有路径.md) + * [0236.二叉树的最近公共祖先](https://github.com/youngyangyang04/leetcode/blob/master/problems/0236.二叉树的最近公共祖先.md) + * [0106.从中序与后序遍历序列构造二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0106.从中序与后序遍历序列构造二叉树.md) + * [0105.从前序与中序遍历序列构造二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0105.从前序与中序遍历序列构造二叉树.md) * [0654.最大二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0654.最大二叉树.md) * [0617.合并二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0617.合并二叉树.md) * [0700.二叉搜索树中的搜索](https://github.com/youngyangyang04/leetcode/blob/master/problems/0700.二叉搜索树中的搜索.md) * [0098.验证二叉搜索树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0098.验证二叉搜索树.md) + * [0530.二叉搜索树的最小绝对差](https://github.com/youngyangyang04/leetcode/blob/master/problems/0530.二叉搜索树的最小绝对差.md) + * [0501.二叉搜索树中的众数](https://github.com/youngyangyang04/leetcode/blob/master/problems/0501.二叉搜索树中的众数.md) + * [0235.二叉搜索树的最近公共祖先](https://github.com/youngyangyang04/leetcode/blob/master/problems/0235.二叉搜索树的最近公共祖先.md) * [0701.二叉搜索树中的插入操作](https://github.com/youngyangyang04/leetcode/blob/master/problems/0701.二叉搜索树中的插入操作.md) * [0450.删除二叉搜索树中的节点](https://github.com/youngyangyang04/leetcode/blob/master/problems/0450.删除二叉搜索树中的节点.md) + * [0669.修剪二叉搜索树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0669.修剪二叉搜索树.md) + * [0108.将有序数组转换为二叉搜索树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0108.将有序数组转换为二叉搜索树.md) + * [0538.把二叉搜索树转换为累加树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0538.把二叉搜索树转换为累加树.md) + * [0968.监控二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0968.监控二叉树.md) * 回溯经典题目 @@ -278,15 +308,17 @@ |[0094.二叉树的中序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0094.二叉树的中序遍历.md) |树 |中等|**递归** **迭代/栈**| |[0098.验证二叉搜索树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0098.验证二叉搜索树.md) |树 |中等|**递归**| |[0100.相同的树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0100.相同的树.md) |树 |简单|**递归** | -|[0101.对称二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0101.对称二叉树.md) |树 |简单|**递归** **迭代/队列/栈**| +|[0101.对称二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0101.对称二叉树.md) |树 |简单|**递归** **迭代/队列/栈** 和100. 相同的树 相似| |[0102.二叉树的层序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md) |树 |中等|**广度优先搜索/队列**| |[0104.二叉树的最大深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0104.二叉树的最大深度.md) |树 |简单|**递归** **迭代/队列/BFS**| -|[0105.从前序与中序遍历序列构造二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0105.从前序与中序遍历序列构造二叉树.md) |树 |中等|**递归**| -|[0106.从中序与后序遍历序列构造二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0106.从中序与后序遍历序列构造二叉树.md) |树 |中等|**递归**| +|[0105.从前序与中序遍历序列构造二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0105.从前序与中序遍历序列构造二叉树.md) |二叉树 |中等|**递归**| +|[0106.从中序与后序遍历序列构造二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0106.从中序与后序遍历序列构造二叉树.md) |二叉树 |中等|**递归** 根据数组构造二叉树| |[0107.二叉树的层次遍历II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0107.二叉树的层次遍历II.md) |树 |简单|**广度优先搜索/队列/BFS**| -|[0110.平衡二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0110.平衡二叉树.md) |树 |简单|**递归**| -|[0111.二叉树的最小深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0111.二叉树的最小深度.md) |树 |简单|**递归** **队列/BFS**| -|[0112.路径总和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0112.路径总和.md) |树 |简单|**深度优先搜索/递归** **回溯** **栈**| +|[0108.将有序数组转换为二叉搜索树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0108.将有序数组转换为二叉搜索树.md) |二叉搜索树 |中等|**递归** **迭代** 通过递归函数返回值构造树| +|[0110.平衡二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0110.平衡二叉树.md) |二叉树 |简单|**递归**| +|[0111.二叉树的最小深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0111.二叉树的最小深度.md) |二叉树 |简单|**递归** **队列/BFS**| +|[0112.路径总和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0112.路径总和.md) |二叉树树 |简单|**深度优先搜索/递归** **回溯** **栈** 思考递归函数什么时候需要返回值| +|[0113.路径总和II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0113.路径总和II.md) |二叉树树 |简单|**深度优先搜索/递归** **回溯** **栈**| |[0116.填充每个节点的下一个右侧节点指针](https://github.com/youngyangyang04/leetcode/blob/master/problems/0116.填充每个节点的下一个右侧节点指针.md) |二叉树 |中等|**递归** **迭代/广度优先搜索**| |[0117.填充每个节点的下一个右侧节点指针II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0117.填充每个节点的下一个右侧节点指针II.md) |二叉树 |中等|**递归** **迭代/广度优先搜索**| |[0131.分割回文串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md) |回溯 |中等|**回溯**| @@ -311,7 +343,7 @@ |[0226.翻转二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0226.翻转二叉树.md) |二叉树 |简单| **递归** **迭代**| |[0232.用栈实现队列](https://github.com/youngyangyang04/leetcode/blob/master/problems/0232.用栈实现队列.md) | 栈 |简单| **栈** | |[0235.二叉搜索树的最近公共祖先](https://github.com/youngyangyang04/leetcode/blob/master/problems/0235.二叉搜索树的最近公共祖先.md) | 二叉搜索树 |简单| **递归** **迭代** | -|[0236.二叉树的最近公共祖先](https://github.com/youngyangyang04/leetcode/blob/master/problems/0236.二叉树的最近公共祖先.md) | 二叉树 |中等| **递归/回溯** | +|[0236.二叉树的最近公共祖先](https://github.com/youngyangyang04/leetcode/blob/master/problems/0236.二叉树的最近公共祖先.md) | 二叉树 |中等| **递归/回溯** 与其说是递归,不如说是回溯| |[0237.删除链表中的节点](https://github.com/youngyangyang04/leetcode/blob/master/problems/0237.删除链表中的节点.md) |链表 |简单| **原链表移除** **添加虚拟节点** 递归| |[0239.滑动窗口最大值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0239.滑动窗口最大值.md) |滑动窗口/队列 |困难| **单调队列**| |[0242.有效的字母异位词](https://github.com/youngyangyang04/leetcode/blob/master/problems/0242.有效的字母异位词.md) |哈希表 |简单| **哈希**| @@ -336,29 +368,32 @@ |[0513.找树左下角的值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0513.找树左下角的值.md) |二叉树 |中等|**递归** **迭代**| |[0515.在每个树行中找最大值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0515.在每个树行中找最大值.md) |二叉树 |简单|**广度优先搜索/队列**| |[0530.二叉搜索树的最小绝对差](https://github.com/youngyangyang04/leetcode/blob/master/problems/0530.二叉搜索树的最小绝对差.md) |二叉树搜索树 |简单|**递归** **迭代**| -|[0538.把二叉搜索树转换为累加树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0538.把二叉搜索树转换为累加树.md) |二叉树 |简单|**递归** **迭代**| +|[0538.把二叉搜索树转换为累加树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0538.把二叉搜索树转换为累加树.md) |二叉搜索树 |简单|**递归** **迭代**| |[0541.反转字符串II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0541.反转字符串II.md) |字符串 |简单| **模拟**| |[0559.N叉树的最大深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0559.N叉树的最大深度.md) |N叉树 |简单| **递归**| |[0572.另一个树的子树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0572.另一个树的子树.md) |二叉树 |简单| **递归**| |[0575.分糖果](https://github.com/youngyangyang04/leetcode/blob/master/problems/0575.分糖果.md) |哈希表 |简单|**哈希**| -|[0589.N叉树的前序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0589.N叉树的前序遍历.md) |树 |简单|**递归** **栈/迭代**| -|[0590.N叉树的后序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0590.N叉树的后序遍历.md) |树 |简单|**递归** **栈/迭代**| +|[0589.N叉树的前序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0589.N叉树的前序遍历.md) |N叉树 |简单|**递归** **栈/迭代**| +|[0590.N叉树的后序遍历](https://github.com/youngyangyang04/leetcode/blob/master/problems/0590.N叉树的后序遍历.md) |N叉树 |简单|**递归** **栈/迭代**| |[0617.合并二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0617.合并二叉树.md) |树 |简单|**递归** **迭代**| |[0637.二叉树的层平均值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0637.二叉树的层平均值.md) |树 |简单|**广度优先搜索/队列**| |[0654.最大二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0654.最大二叉树.md) |树 |中等|**递归**| |[0685.冗余连接II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0685.冗余连接II.md) | 并查集/树/图 |困难|**并查集**| |[0669.修剪二叉搜索树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0669.修剪二叉搜索树.md) | 二叉搜索树/二叉树 |简单|**递归** **迭代**| -|[0700.二叉搜索树中的搜索](https://github.com/youngyangyang04/leetcode/blob/master/problems/0700.二叉搜索树中的搜索.md) |树 |简单|**递归** **迭代**| -|[0701.二叉搜索树中的插入操作](https://github.com/youngyangyang04/leetcode/blob/master/problems/0701.二叉搜索树中的插入操作.md) |树 |简单|**递归** **迭代**| +|[0700.二叉搜索树中的搜索](https://github.com/youngyangyang04/leetcode/blob/master/problems/0700.二叉搜索树中的搜索.md) |二叉搜索树 |简单|**递归** **迭代**| +|[0701.二叉搜索树中的插入操作](https://github.com/youngyangyang04/leetcode/blob/master/problems/0701.二叉搜索树中的插入操作.md) |二叉搜索树 |简单|**递归** **迭代**| |[0705.设计哈希集合](https://github.com/youngyangyang04/leetcode/blob/master/problems/0705.设计哈希集合.md) |哈希表 |简单|**模拟**| |[0707.设计链表](https://github.com/youngyangyang04/leetcode/blob/master/problems/0707.设计链表.md) |链表 |中等|**模拟**| +|[0763.划分字母区间](https://github.com/youngyangyang04/leetcode/blob/master/problems/0763.划分字母区间.md) |贪心 |中等|**双指针/贪心** 体现贪心尽可能多的思想| |[0739.每日温度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0739.每日温度.md) |栈 |中等|**单调栈** 适合单调栈入门| |[0841.钥匙和房间](https://github.com/youngyangyang04/leetcode/blob/master/problems/0841.钥匙和房间.md) |孤岛问题 |中等|**bfs** **dfs**| |[0844.比较含退格的字符串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0844.比较含退格的字符串.md) |字符串 |简单|**栈** **双指针优化** 使用栈的思路但没有必要使用栈| |[0925.长按键入](https://github.com/youngyangyang04/leetcode/blob/master/problems/0925.长按键入.md) |字符串 |简单|**双指针/模拟** 是一道模拟类型的题目| +|[0968.监控二叉树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0968.监控二叉树.md) |二叉树 |困难|**贪心** 贪心与二叉树的结合| |[0977.有序数组的平方](https://github.com/youngyangyang04/leetcode/blob/master/problems/0977.有序数组的平方.md) |数组 |中等|**双指针** 还是比较巧妙的| |[1002.查找常用字符](https://github.com/youngyangyang04/leetcode/blob/master/problems/1002.查找常用字符.md) |栈 |简单|**栈**| |[1047.删除字符串中的所有相邻重复项](https://github.com/youngyangyang04/leetcode/blob/master/problems/1047.删除字符串中的所有相邻重复项.md) |哈希表 |简单|**哈希表/数组**| +|[1382.将二叉搜索树变平衡](https://github.com/youngyangyang04/leetcode/blob/master/problems/1047.删除字符串中的所有相邻重复项.md) |二叉搜索树 |中等|**递归** **迭代** 98和108的组合题目| |[剑指Offer05.替换空格](https://github.com/youngyangyang04/leetcode/blob/master/problems/剑指Offer05.替换空格.md) |字符串 |简单|**双指针**| |[ 剑指Offer58-I.翻转单词顺序](https://github.com/youngyangyang04/leetcode/blob/master/problems/剑指Offer05.替换空格.md) |字符串 |简单|**模拟/双指针**| |[剑指Offer58-II.左旋转字符串](https://github.com/youngyangyang04/leetcode/blob/master/problems/剑指Offer58-II.左旋转字符串.md) |字符串 |简单|**反转操作**| diff --git a/pics/108.将有序数组转换为二叉搜索树.png b/pics/108.将有序数组转换为二叉搜索树.png new file mode 100644 index 00000000..7d25f99d Binary files /dev/null and b/pics/108.将有序数组转换为二叉搜索树.png differ diff --git a/pics/234.回文链表.png b/pics/234.回文链表.png new file mode 100644 index 00000000..285c73bb Binary files /dev/null and b/pics/234.回文链表.png differ diff --git a/pics/538.把二叉搜索树转换为累加树.png b/pics/538.把二叉搜索树转换为累加树.png index 1417fef9..27077f7b 100644 Binary files a/pics/538.把二叉搜索树转换为累加树.png and b/pics/538.把二叉搜索树转换为累加树.png differ diff --git a/pics/763.划分字母区间.png b/pics/763.划分字母区间.png new file mode 100644 index 00000000..0c1da0f3 Binary files /dev/null and b/pics/763.划分字母区间.png differ diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 0089d3fc..9b8295b1 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -3,6 +3,12 @@ https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorde > 给出两个序列 +看完本文,可以一起解决如下两道题目 + +* 106.从中序与后序遍历序列构造二叉树 +* 105.从前序与中序遍历序列构造二叉树 + + # 106.从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树。 @@ -383,7 +389,7 @@ public: }; ``` -# 105. 从前序与中序遍历序列构造二叉树 +# 105.从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树。 diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md index 6a406ffd..3afc8d6a 100644 --- a/problems/0108.将有序数组转换为二叉搜索树.md +++ b/problems/0108.将有序数组转换为二叉搜索树.md @@ -1,28 +1,122 @@ +> 构造二叉搜索树,一不小心就平衡了 -## 思路 +# 108.将有序数组转换为二叉搜索树 -要考率 和 普通数组转成二叉树有什么差别 +将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 -注意这里是构造平衡二叉搜索树,其实 这里不用强调,因为数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从中间取值,不可能随机取,自找麻烦 +本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 -一想 这道题目还是有难度的, +示例: -一定是递归 分治 +![108.将有序数组转换为二叉搜索树](https://img-blog.csdnimg.cn/20201022164420763.png) -循环不变量 的题目列表 +# 思路 -注意答案不是唯一的 +做这道题目之前大家可以了解一下这几道: -输入:[-10,-3,0,5,9] -输出:[0,-10,5,null,-3,null,9] -预期结果:[0,-3,9,-10,null,5] +* [106.从中序与后序遍历序列构造二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) +* [654.最大二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中其实已经讲过了,如果根据数组构造一颗二叉树。 +* [701.二叉搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA) +* [450.删除二叉搜索树中的节点](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw) + + +进入正题: + +题目中说要转换为一棵高度平衡二叉搜索树。这和转换为一棵普通二叉搜索树有什么差别呢? + +其实这里不用强调平衡二叉搜索树,数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取,**所以想构成不平衡的二叉树是自找麻烦**。 + + +在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)和[二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中其实已经讲过了,如果根据数组构造一颗二叉树。 + +**本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间**。 + +本题其实要比[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 和 [二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)简单一些,因为有序数组构造二叉搜索树,寻找分割点就比较容易了。 + +分割点就是数组中间位置的节点。 + +那么为问题来了,如果数组长度为偶数,中间节点有两个,取哪一个? + +取哪一个都可以,只不过构成了不同的平衡二叉搜索树。 + +例如:输入:[-10,-3,0,5,9] + +如下两棵树,都是这个数组的平衡二叉搜索树: + + + +如果要分割的数组长度为偶数的时候,中间元素为两个,是取左边元素 就是树1,取右边元素就是树2。 + +**这也是题目中强调答案不是唯一的原因。 理解这一点,这道题目算是理解到位了**。 + +## 递归 + +递归三部曲: + +* 确定递归函数返回值及其参数 + +删除二叉树节点,增加二叉树节点,都是用递归函数的返回值来完成,这样是比较方便的。 + +相信大家如果仔细看了[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)和[二叉树:搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw),一定会对递归函数返回值的作用深有感触。 + +那么本题要构造二叉树,依然用递归函数的返回值来构造中节点的左右孩子。 + +再来看参数,首先是传入数组,然后就是左下表left和右下表right,我们在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)中提过,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下表来操作原数组。 + +所以代码如下: + +``` +// 左闭右闭区间[left, right] +TreeNode* traversal(vector& nums, int left, int right) +``` + +这里注意,**我这里定义的是左闭右闭区间,在不断分割的过程中,也会坚持左闭右闭的区间,这又涉及到我们讲过的循环不变量**。 + +在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg),[35.搜索插入位置](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q) 和[59.螺旋矩阵II](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)都详细讲过循环不变量。 + + +* 确定递归终止条件 + +这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。 + +代码如下: + +``` +if (left > right) return nullptr; +``` + +* 确定单层递归的逻辑 + +首先取数组中间元素的位置,不难写出`int mid = (left + right) / 2;`,**这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在[二分法](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)中尤其需要注意!** + +所以可以这么写:`int mid = left + ((right - left) / 2);` + +但本题leetcode的测试数据并不会越界,所以怎么写都可以。但需要有这个意识! + +取了中间位置,就开始以中间位置的元素构造节点,代码:`TreeNode* root = new TreeNode(nums[mid]);`。 + +接着划分区间,root的左孩子接住下一层左区间的构造节点,右孩子接住下一层右区间构造的节点。 + +最后返回root节点,单层递归整体代码如下: + +``` +int mid = left + ((right - left) / 2); +TreeNode* root = new TreeNode(nums[mid]); +root->left = traversal(nums, left, mid - 1); +root->right = traversal(nums, mid + 1, right); +return root; +``` + +这里`int mid = left + ((right - left) / 2);`的写法相当于是如果数组长度为偶数,中间位置有两个元素,取靠左边的。 + +* 递归整体代码如下: ``` class Solution { private: TreeNode* traversal(vector& nums, int left, int right) { if (left > right) return nullptr; - int mid = (left + right) / 2; // 注意越界 + int mid = left + ((right - left) / 2); TreeNode* root = new TreeNode(nums[mid]); root->left = traversal(nums, left, mid - 1); root->right = traversal(nums, mid + 1, right); @@ -36,3 +130,68 @@ public: }; ``` +**注意:在调用traversal的时候为什么传入的left和right为什么是0和nums.size() - 1,因为定义的区间为左闭右闭**。 + + +## 迭代法 + +迭代法可以通过三个队列来模拟,一个队列放遍历的节点,一个队列放左区间下表,一个队列放右区间下表。 + +模拟的就是不断分割的过程,C++代码如下:(我已经详细注释) + +``` +class Solution { +public: + TreeNode* sortedArrayToBST(vector& nums) { + if (nums.size() == 0) return nullptr; + + TreeNode* root = new TreeNode(0); // 初始根节点 + queue nodeQue; // 放遍历的节点 + queue leftQue; // 保存左区间下表 + queue rightQue; // 保存右区间下表 + nodeQue.push(root); // 根节点入队列 + leftQue.push(0); // 0为左区间下表初始位置 + rightQue.push(nums.size() - 1); // nums.size() - 1为右区间下表初始位置 + + while (!nodeQue.empty()) { + TreeNode* curNode = nodeQue.front(); + nodeQue.pop(); + int left = leftQue.front(); leftQue.pop(); + int right = rightQue.front(); rightQue.pop(); + int mid = left + ((right - left) / 2); + + curNode->val = nums[mid]; // 将mid对应的元素给中间节点 + + if (left <= mid - 1) { // 处理左区间 + curNode->left = new TreeNode(0); + nodeQue.push(curNode->left); + leftQue.push(left); + rightQue.push(mid - 1); + } + + if (right >= mid + 1) { // 处理右区间 + curNode->right = new TreeNode(0); + nodeQue.push(curNode->right); + leftQue.push(mid + 1); + rightQue.push(right); + } + } + return root; + } +}; +``` + +# 总结 + +**在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 和 [二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。 + +其实思路也是一样的,不断中间分割,然后递归处理左区间,右区间,也可以说是分治。 + +此时相信大家应该对通过递归函数的返回值来增删二叉树很熟悉了,这也是常规操作。 + +在定义区间的过程中我们又一次强调了循环不变量的重要性。 + +最后依然给出迭代的方法,其实就是模拟取中间元素,然后不断分割去构造二叉树的过程。 + +**就酱,如果对你有帮助的话,也转发给身边需要的同学吧!** + diff --git a/problems/0234.回文链表.md b/problems/0234.回文链表.md new file mode 100644 index 00000000..d37044d7 --- /dev/null +++ b/problems/0234.回文链表.md @@ -0,0 +1,122 @@ + +## 题目链接 +https://leetcode-cn.com/problems/palindrome-linked-list/ + +## 思路 + +### 数组模拟 + +最直接的想法,就是把链表装成数组,然后再判断是否回文。 + +代码也比较简单。如下: + +``` +class Solution { +public: + bool isPalindrome(ListNode* head) { + vector vec; + ListNode* cur = head; + while (cur) { + vec.push_back(cur->val); + cur = cur->next; + } + // 比较数组回文 + for (int i = 0, j = vec.size() - 1; i < j; i++, j--) { + if (vec[i] != vec[j]) return false; + } + return true; + } +}; +``` + +上面代码可以在优化,就是先求出链表长度,然后给定vector的初始长度,这样避免vector每次添加节点重新开辟空间 + +``` +class Solution { +public: + bool isPalindrome(ListNode* head) { + + ListNode* cur = head; + int length = 0; + while (cur) { + length++; + cur = cur->next; + } + vector vec(length, 0); // 给定vector的初始长度,这样避免vector每次添加节点重新开辟空间 + cur = head; + int index = 0; + while (cur) { + vec[index++] = cur->val; + cur = cur->next; + } + // 比较数组回文 + for (int i = 0, j = vec.size() - 1; i < j; i++, j--) { + if (vec[i] != vec[j]) return false; + } + return true; + } +}; + +``` + +### 反转后半部分链表 + +分为如下几步: + +* 用快慢指针,快指针有两步,慢指针走一步,快指针遇到终止位置时,慢指针就在链表中间位置 +* 同时用pre记录慢指针指向节点的前一个节点,用来分割链表 +* 将链表分为前后均等两部分,如果链表长度是奇数,那么后半部分多一个节点 +* 将后半部分反转 ,得cur2,前半部分为cur1 +* 按照cur1的长度,一次比较cur1和cur2的节点数值 + +如图所示: + + + +代码如下: + +``` +class Solution { +public: + bool isPalindrome(ListNode* head) { + if (head == nullptr || head->next == nullptr) return true; + ListNode* slow = head; // 慢指针,找到链表中间分位置,作为分割 + ListNode* fast = head; + ListNode* pre = head; // 记录慢指针的前一个节点,用来分割链表 + while (fast && fast->next) { + pre = slow; + slow = slow->next; + fast = fast->next->next; + } + pre->next = nullptr; // 分割链表 + + ListNode* cur1 = head; // 前半部分 + ListNode* cur2 = reverseList(slow); // 反转后半部分,总链表长度如果是奇数,cur2比cur1多一个节点 + + // 开始两个链表的比较 + while (cur1) { + if (cur1->val != cur2->val) return false; + cur1 = cur1->next; + cur2 = cur2->next; + } + return true; + } + // 反转链表 + ListNode* reverseList(ListNode* head) { + ListNode* temp; // 保存cur的下一个节点 + ListNode* cur = head; + ListNode* pre = nullptr; + while(cur) { + temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next + cur->next = pre; // 翻转操作 + // 更新pre 和 cur指针 + pre = cur; + cur = temp; + } + return pre; + } +}; +``` + +栈 + diff --git a/problems/0402.移掉K位数字.md b/problems/0402.移掉K位数字.md new file mode 100644 index 00000000..c7112bff --- /dev/null +++ b/problems/0402.移掉K位数字.md @@ -0,0 +1,11 @@ + +## 思路 + +https://www.cnblogs.com/gzshan/p/12560566.html 图不错 + +有点难度 + + +暴力的解法,其实也不是那么好写的, 首字符去0,k没消耗完,等等这些情况 + +有点难,卡我很久 diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md index f50a03f1..84dada49 100644 --- a/problems/0538.把二叉搜索树转换为累加树.md +++ b/problems/0538.把二叉搜索树转换为累加树.md @@ -3,28 +3,109 @@ https://leetcode-cn.com/problems/convert-bst-to-greater-tree/ -## 思路 +> 祝大家1024节日快乐!! -一看到累加树,相信很多小伙伴一脸懵逼,如何累加,遇到一个节点,然后在遍历其他节点累加?怎么一想这么麻烦呢。 +今天应该是一个程序猿普天同庆的日子,所以今天的题目比较简单,只要认真把前面每天的文章都看了,今天的题目就是分分钟的事了,大家可以愉快过节! -然后发现这是一颗二叉搜索树,二叉搜索树啊,这是有序的啊。 +# 538.把二叉搜索树转换为累加树 + +题目链接:https://leetcode-cn.com/problems/convert-bst-to-greater-tree/ + +给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 + +提醒一下,二叉搜索树满足下列约束条件: + +节点的左子树仅包含键 小于 节点键的节点。 +节点的右子树仅包含键 大于 节点键的节点。 +左右子树也必须是二叉搜索树。 + +示例 1: + +![538.把二叉搜索树转换为累加树](https://img-blog.csdnimg.cn/20201023160751832.png) + +输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8] +输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8] + +示例 2: +输入:root = [0,null,1] +输出:[1,null,1] + +示例 3: +输入:root = [1,0,2] +输出:[3,3,2] + +示例 4: +输入:root = [3,2,4,1] +输出:[7,9,4,10] + +提示: + +* 树中的节点数介于 0 和 104 之间。 +* 每个节点的值介于 -104 和 104 之间。 +* 树中的所有值 互不相同 。 +* 给定的树为二叉搜索树。 + +# 思路 + +一看到累加树,相信很多小伙伴都会疑惑:如何累加?遇到一个节点,然后在遍历其他节点累加?怎么一想这么麻烦呢。 + +然后再发现这是一颗二叉搜索树,二叉搜索树啊,这是有序的啊。 那么有序的元素如果求累加呢? -**其实这就是一棵树,大家可能看起来有点别扭,换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13],大家是不是感觉这就是送分题了。** +**其实这就是一棵树,大家可能看起来有点别扭,换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13],是不是感觉这就简单了。** -为什么变成数组就是送分题了呢,因为数组大家都知道怎么遍历啊,从后向前,挨个累加就完事了,这换成了二叉搜索树,看起来就别扭了一些是不是。 +为什么变成数组就是感觉简单了呢? -那么知道如何遍历这个二叉树,也就迎刃而解了,从树中可以看出累加的顺讯是 右中左,所以我们需要中序遍历反过来遍历这个二叉树,然后顺序累加就可以了。 +因为数组大家都知道怎么遍历啊,从后向前,挨个累加就完事了,这换成了二叉搜索树,看起来就别扭了一些是不是。 + +那么知道如何遍历这个二叉树,也就迎刃而解了,**从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了**。 + +## 递归 遍历顺序如图所示: +本题依然需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。 -以下我给出一种递归的写法,两种迭代法的写法,别问我为什么写出了这么多写法,把我写的这个题解[彻底吃透二叉树的前中后序递归法和迭代法!!](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/che-di-chi-tou-er-cha-shu-de-qian-zhong-hou-xu-d-2/)看了,你也能分分钟写出来三种写法![机智] +pre指针的使用技巧,我们在[二叉树:搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ)和[二叉树:我的众数是多少?](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg)都提到了,这是常用的操作手段。 -## C++递归代码 +* 递归函数参数以及返回值 + +这里很明确了,不需要递归函数的返回值做什么操作了,要遍历整棵树。 + +同时需要定义一个全局变量pre,用来保存cur节点的前一个节点的数值,定义为int型就可以了。 + +代码如下: + +``` +int pre; // 记录前一个节点的数值 +void traversal(TreeNode* cur) +``` + +* 确定终止条件 + +遇空就终止。 + +``` +if (cur == NULL) return; +``` + +* 确定单层递归的逻辑 + +注意**要右中左来遍历二叉树**, 中节点的处理逻辑就是让cur的数值加上前一个节点的数值。 + +代码如下: + +``` +traversal(cur->right); // 右 +cur->val += pre; // 中 +pre = cur->val; +traversal(cur->left); // 左 +``` + +递归法整体代码如下: ``` class Solution { @@ -46,7 +127,11 @@ public: }; ``` -## C++迭代法(一)代码 +## 迭代法 + +迭代法其实就是中序模板题了,在[二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)和[二叉树:前中后序统一方式迭代法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)可以选一种自己习惯的写法。 + +这里我给出其中的一种,代码如下: ``` class Solution { @@ -77,40 +162,12 @@ public: }; ``` -## C++迭代法(二)代码 +# 总结 -``` -class Solution { -private: - int pre; // 记录前一个节点的数值 - void traversal(TreeNode* root) { - stack st; - if (root != NULL) st.push(root); - while (!st.empty()) { - TreeNode* node = st.top(); - if (node != NULL) { - st.pop(); - if (node->left) st.push(node->left); // 左 +经历了前面各种二叉树增删改查的洗礼之后,这道题目应该比较简单了。 - st.push(node); // 中 - st.push(NULL); +**好了,二叉树已经接近尾声了,接下来就是要对二叉树来一个大总结了**。 + +最后再次祝大家1024节日快乐,哈哈哈! - if (node->right) st.push(node->right); // 右 - } else { - st.pop(); - node = st.top(); - st.pop(); - node->val += pre; // 处理中间节点 - pre = node->val; - } - } - } -public: - TreeNode* convertBST(TreeNode* root) { - pre = 0; - traversal(root); - return root; - } -}; -``` diff --git a/problems/0669.修剪二叉搜索树.md b/problems/0669.修剪二叉搜索树.md index d8e40aba..641416b0 100644 --- a/problems/0669.修剪二叉搜索树.md +++ b/problems/0669.修剪二叉搜索树.md @@ -97,7 +97,7 @@ if (root->val < low) { } ``` -如果root(当前节点)的元素小于high的,那么应该递归左子树,并返回左子树符合条件的头结点。 +如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。 代码如下: diff --git a/problems/0739.每日温度.md b/problems/0739.每日温度.md index 83acc50d..12d9a55f 100644 --- a/problems/0739.每日温度.md +++ b/problems/0739.每日温度.md @@ -51,3 +51,4 @@ public: } }; ``` +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0763.划分字母区间.md b/problems/0763.划分字母区间.md new file mode 100644 index 00000000..6a0716a3 --- /dev/null +++ b/problems/0763.划分字母区间.md @@ -0,0 +1,41 @@ +## 题目链接 +https://leetcode-cn.com/problems/partition-labels/ + +## 思路 + +一想到分割字符串就想到了回溯,但本题其实不用那么复杂。 + +可以分为如下两步: + +* 统计每一个字符最后出现的位置 +* 从头遍历字符,如果找到之前字符最大出现位置下标和当前下标相等,则找到了分割点 + +如图: + + + +明白原理之后,代码并不复杂,如下: + +``` +class Solution { +public: + vector partitionLabels(string S) { + int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置 + for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置 + hash[S[i] - 'a'] = i; + } + vector result; + int left = 0; + int right = 0; + for (int i = 0; i < S.size(); i++) { + right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界 + if (i == right) { + result.push_back(right - left + 1); + left = i + 1; + } + } + return result; + } +}; +``` +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0841.钥匙和房间.md b/problems/0841.钥匙和房间.md index e30d18f1..16473f1a 100644 --- a/problems/0841.钥匙和房间.md +++ b/problems/0841.钥匙和房间.md @@ -80,3 +80,5 @@ public: } }; ``` + +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0844.比较含退格的字符串.md b/problems/0844.比较含退格的字符串.md index a47bdbb3..47031a70 100644 --- a/problems/0844.比较含退格的字符串.md +++ b/problems/0844.比较含退格的字符串.md @@ -118,3 +118,5 @@ public: * 时间复杂度:O(n + m) * 空间复杂度:O(1) + +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0925.长按键入.md b/problems/0925.长按键入.md index 7890dd9a..6c6ba699 100644 --- a/problems/0925.长按键入.md +++ b/problems/0925.长按键入.md @@ -57,3 +57,5 @@ public: 时间复杂度:O(n) 空间复杂度:O(1) + +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md index dc3fec03..a5dbdefb 100644 --- a/problems/0968.监控二叉树.md +++ b/problems/0968.监控二叉树.md @@ -217,3 +217,4 @@ public: } }; ``` +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0977.有序数组的平方.md b/problems/0977.有序数组的平方.md index 5f09aa76..f5ff9638 100644 --- a/problems/0977.有序数组的平方.md +++ b/problems/0977.有序数组的平方.md @@ -73,3 +73,4 @@ public: 一样的代码多提交几次可能就击败百分之百了..... +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index 106e8e12..f9506010 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -108,3 +108,5 @@ public: } }; ``` + +> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 0b12c129..1962e78d 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -84,5 +84,27 @@ public: }; ``` +当然可以拿字符串直接作为栈,这样省去了栈还要转为字符串的操作。 + +代码如下: + +``` +class Solution { +public: + string removeDuplicates(string S) { + string result; + for(char s : S) { + if(result.empty() || result.back() != s) { + result.push_back(s); + } + else { + result.pop_back(); + } + } + return result; + } +}; +``` + > 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/1382.将二叉搜索树变平衡.md b/problems/1382.将二叉搜索树变平衡.md new file mode 100644 index 00000000..9d3a2b65 --- /dev/null +++ b/problems/1382.将二叉搜索树变平衡.md @@ -0,0 +1,46 @@ + +## 题目地址 +https://leetcode-cn.com/problems/balance-a-binary-search-tree/ + +## 思路 + +这道题目,可以中序遍历把二叉树转变为有序数组,然后在根据有序数组构造平衡二叉搜索树。 + +建议做这道题之前,先看如下两篇题解: +* [98.验证二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q) 学习二叉搜索树的特性 +* [108.将有序数组转换为二叉搜索树](https://mp.weixin.qq.com/s/sy3ygnouaZVJs8lhFgl9mw) 学习如何通过有序数组构造二叉搜索树 + +这两道题目做过之后,本题分分钟就可以做出来了。 + +代码如下: + +``` +class Solution { +private: + vector vec; + // 有序树转成有序数组 + void traversal(TreeNode* cur) { + if (cur == nullptr) { + return; + } + traversal(cur->left); + vec.push_back(cur->val); + traversal(cur->right); + } + 有序数组转平衡二叉树 + TreeNode* getTree(vector& nums, int left, int right) { + if (left > right) return nullptr; + int mid = left + ((right - left) / 2); + TreeNode* root = new TreeNode(nums[mid]); + root->left = getTree(nums, left, mid - 1); + root->right = getTree(nums, mid + 1, right); + return root; + } + +public: + TreeNode* balanceBST(TreeNode* root) { + traversal(root); + return getTree(vec, 0, vec.size() - 1); + } +}; +```