This commit is contained in:
youngyangyang04
2020-10-22 09:15:34 +08:00
parent 6f0f3f71d5
commit 757cc9a2ed
11 changed files with 304 additions and 24 deletions

View File

@ -41,7 +41,6 @@ public:
本题是从栈底到栈头 从小到大,和 接雨水正好反过来。
```
class Solution {
public:

View File

@ -0,0 +1,38 @@
## 思路
要考率 和 普通数组转成二叉树有什么差别
注意这里是构造平衡二叉搜索树,其实 这里不用强调,因为数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从中间取值,不可能随机取,自找麻烦
一想 这道题目还是有难度的,
一定是递归 分治
循环不变量 的题目列表
注意答案不是唯一的
输入:[-10,-3,0,5,9]
输出:[0,-10,5,null,-3,null,9]
预期结果:[0,-3,9,-10,null,5]
```
class Solution {
private:
TreeNode* traversal(vector<int>& nums, int left, int right) {
if (left > right) return nullptr;
int mid = (left + right) / 2; // 注意越界
TreeNode* root = new TreeNode(nums[mid]);
root->left = traversal(nums, left, mid - 1);
root->right = traversal(nums, mid + 1, right);
return root;
}
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* root = traversal(nums, 0, nums.size() - 1);
return root;
}
};
```

View File

@ -137,6 +137,8 @@ public:
};
```
### 普通二叉树的删除方式
这里我在介绍一种通用的删除,普通二叉树的删除方式(没有使用搜索树的特性,遍历整棵树),用交换值的操作来删除目标节点。
代码中目标节点(要删除的节点)被操作了两次:

View File

@ -0,0 +1,35 @@
## 链接
https://leetcode-cn.com/problems/next-greater-element-i/
## 思路
两个数组逻辑还是有点绕
最好还是把所有情况列出来
```
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
vector<int> result(nums1.size(), -1);
if (nums1.size() == 0) return result;
unordered_map<int, int> umap; // key:下表元素value下表
for (int i = 0; i < nums1.size(); i++) {
umap[nums1[i]] = i;
}
st.push(0);
for (int i = 1; i < nums2.size(); i++) {
while (!st.empty() && nums2[i] > nums2[st.top()]) {
if (umap.count(nums2[st.top()]) > 0) { // 看map里是否存在这个元素
int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()] 在 nums1中的下表
result[index] = nums2[i];
}
st.pop();
}
st.push(i);
}
return result;
}
};
```

View File

@ -0,0 +1,62 @@
## 链接
https://leetcode-cn.com/problems/next-greater-element-ii/
## 思路
可以把两个数组拼接在一起
代码性能不行啊,得找找优化的方式
```
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> nums1(nums.begin(), nums.end());
nums.insert(nums.end(), nums1.begin(), nums1.end());
vector<int> result(nums.size(), -1);
if (nums.size() == 0) return result;
stack<int> st;
st.push(0);
for (int i = 0; i < nums.size(); i++) {
while (!st.empty() && nums[i] > nums[st.top()]) {
result[st.top()] = nums[i];
st.pop();
}
st.push(i);
}
result.resize(nums.size() / 2);
return result;
}
};
```
这样好像能高一些
```
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> nums1(nums.begin(), nums.end());
nums.resize(nums.size() * 2);
int h = nums.size() / 2;
for (int i = 0; i < nums.size() / 2; i++) {
nums[h + i] = nums[i];
}
//nums.insert(nums.end(), nums1.begin(), nums1.end());
vector<int> result(nums.size(), -1);
if (nums.size() == 0) return result;
stack<int> st;
st.push(0);
for (int i = 0; i < nums.size(); i++) {
while (!st.empty() && nums[i] > nums[st.top()]) {
result[st.top()] = nums[i];
st.pop();
}
st.push(i);
}
result.resize(nums.size() / 2);
return result;
}
};
```

View File

@ -1,8 +1,16 @@
## 题目链接
https://leetcode-cn.com/problems/trim-a-binary-search-tree/
> 如果不对递归有深刻的理解,本题有点难
> 单纯移除一个节点那还不够,要修剪!
# 669. 修剪二叉搜索树
题目链接https://leetcode-cn.com/problems/trim-a-binary-search-tree/
给定一个二叉搜索树同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
![669.修剪二叉搜索树](https://img-blog.csdnimg.cn/20201014173115788.png)
@ -11,11 +19,13 @@
# 思路
相信看到这道题目大家都感觉是一道简单题事实上leetcode上也明是简单)。
相信看到这道题目大家都感觉是一道简单题事实上leetcode上也明是简单)。
但还真的不简单!
## 递归法
直接想法就是:递归处理,然后遇到 `root->val < low || root->val > high` 的时候直接return NULL一波修,赶紧利落。
直接想法就是:递归处理,然后遇到 `root->val < low || root->val > high` 的时候直接return NULL一波修,赶紧利落。
不难写出如下代码:
@ -31,7 +41,7 @@ public:
};
```
**然而[1, 3]区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的还要考虑节点0的右子树**
**然而[1, 3]区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的还要考虑节点0的右子树**
我们在重新关注一下第二个示例,如图:
@ -43,7 +53,7 @@ public:
其实不用重构那么复杂。
在上图中我们发现节点0并不符合区间要求那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了就是把元素0减掉),如图:
在上图中我们发现节点0并不符合区间要求那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了就是把节点0从二叉树中移除),如图:
<img src='../pics/669.修剪二叉搜索树1.png' width=600> </img></div>
@ -52,14 +62,13 @@ public:
* 确定递归函数的参数以及返回值
首先**我们要返回函数参数节点root为根节点的树 修剪完之后的 新的根节点**这里我们为什么需要返回值呢?
这里我们为什么需要返回值呢?
因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。
因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是要删除节点)的操作
但是有返回值,更方便,可以通过递归函数的返回值来移除节点
但是有返回值,更方便,可以通过 这样的赋值语句:`root->left = trimBST(root->left, int low, int high)` 直接删除root的左孩子如果root的左孩子不在范围内的话
**因为`trimBST(root->left, int low, int high)` 将返回当前root左子树以root->left为根节点的二叉树修剪完之后的新的根节点。**
这样的做法在[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)和[二叉树:搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw)中大家已经了解过了
代码如下:
@ -77,7 +86,7 @@ if (root == nullptr ) return nullptr;
* 确定单层递归的逻辑
如果root当前节点的元素小于low的数值那么应该递归右子树并返回右子树的头结点。
如果root当前节点的元素小于low的数值那么应该递归右子树并返回右子树符合条件的头结点。
代码如下:
@ -88,7 +97,7 @@ if (root->val < low) {
}
```
如果root(当前节点)的元素小于high的那么应该递归左子树并返回左子树的头结点。
如果root(当前节点)的元素小于high的那么应该递归左子树并返回左子树符合条件的头结点。
代码如下:
@ -99,33 +108,43 @@ if (root->val > high) {
}
```
接下来要将处理完左子树的结果赋给root->left处理完右子树的结果赋给root->right。
接下来要将下一层处理完左子树的结果赋给root->left处理完右子树的结果赋给root->right。
最后返回root节点代码如下
```
root->left = trimBST(root->left, low, high); // root->left接入符合条件的左孩子
root->right = trimBST(root->right, low, high); // root->right接入符合条件的右孩子
return root;
```
此时大家是不是还没发现这多余的节点究竟是如何除的?
此时大家是不是还没发现这多余的节点究竟是如何从二叉树中移除的
在回顾一下上面的代码,针对下图中二叉树的情况:
<img src='../pics/669.修剪二叉搜索树1.png' width=600> </img></div>
如下代码相当于把节点0的右孩子节点2返回给上一层
```
if (root->val < low) {
TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点
return right;
}
```
然后如下代码相当于用节点3的左孩子 把下一层返回的 节点0的右孩子节点2 接住。
其实就是通过,这两个语句删除的。
```
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
```
root重新规划root的左右孩子究竟是谁拿图中示例为例此时root为节点3那么trimBST(root->left, low, high)返回的就是节点2`root->left = trimBST(root->left, low, high);` 相当于把节点0删除了。
此时节点3的右孩子就变成了节点2将节点0从二叉树中移除了。
最后整体代码如下:
```
class Solution {
public:
// 注意这里是返回该树的头结点
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == nullptr ) return nullptr;
if (root->val < low) {
@ -159,6 +178,8 @@ public:
};
```
只看代码,其实不太好理解节点是符合移除的,这一块大家可以自己在模拟模拟!
## 迭代法
因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。
@ -212,6 +233,6 @@ public:
**如果不对递归有深刻的理解,这道题目还是有难度的!**
本题我依然给出递归法和迭代法,大家只要掌握递归其实就可以了,如果想进一步学习,就把迭代法也写一写。
本题我依然给出递归法和迭代法,初学者掌握递归就可以了,如果想进一步学习,就把迭代法也写一写。
**就酱,如果学到了,就转发给身边需要的同学吧!**

View File

@ -0,0 +1,53 @@
# 思路
使用递减栈(从大到小 栈底到栈头)
```
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
// 递减栈
stack<int> st;
vector<int> result(T.size(), 0);
st.push(0);
for (int i = 1; i < T.size(); i++) {
if (T[i] < T[st.top()]) { // 把i放入栈
st.push(i);
} else if (T[i] == T[st.top()]) { // 相同也要把i放进去例如 1 1 1 1 2
st.push(i);
} else {
while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
}
return result;
}
};
```
建议一开始 都把每种情况分析好,不要上来看简短的代码,关键逻辑都被隐藏了。
精简代码如下:
```
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> st; // 递减栈
vector<int> result(T.size(), 0);
st.push(0);
for (int i = 1; i < T.size(); i++) {
while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
return result;
}
};
```

View File

@ -0,0 +1,59 @@
## 思路
这道题目一看以为是哈希,仔细一看不行,要有顺序。
所以模拟同时遍历两个数组,进行对比就可以了。
对比的时候需要一下几点:
* name[i] 和 typed[j]相同则i++j++ (继续向后对比)
* name[i] 和 typed[j]不相同
* 看是不是第一位就不相同了也就是j如果等于0那么直接返回false
* 不是第一位不相同就让j跨越重复项移动到重复项之后的位置再次比较name[i] 和typed[j]
* 如果 name[i] 和 typed[j]相同则i++j++ (继续向后对比)
* 不相同返回false
* 对比完之后有两种情况
* name没有匹配完例如name:"pyplrzzzzdsfa" type:"ppyypllr"
* type没有匹配完例如name:"alex" type:"alexxrrrrssda"
动画如下:
<img src='../video/925.长按键入.gif' width=600> </img></div>
上面的逻辑想清楚了不难写出如下C++代码:
```
class Solution {
public:
bool isLongPressedName(string name, string typed) {
int i = 0, j = 0;
while (i < name.size() && j < typed.size()) {
if (name[i] == typed[j]) { // 相同则同时向后匹配
j++; i++;
} else { // 不相同
if (j == 0) return false; // 如果是第一位就不相同直接返回false
// j跨越重复项向后移动同时防止j越界
while(j < typed.size() && typed[j] == typed[j - 1]) j++;
if (name[i] == typed[j]) { // j跨越重复项之后再次和name[i]匹配
j++; i++; // 相同则同时向后匹配
}
else return false;
}
}
// 说明name没有匹配完例如 name:"pyplrzzzzdsfa" type:"ppyypllr"
if (i < name.size()) return false;
// 说明type没有匹配完例如 name:"alex" type:"alexxrrrrssda"
while (j < typed.size()) {
if (typed[j] == typed[j - 1]) j++;
else return false;
}
return true;
}
};
```
时间复杂度O(n)
空间复杂度O(1)