- 剑指 Offer 59 - I. 滑动窗口的最大值">剑指 Offer 59 - I. 滑动窗口的最大值
- 剑指 Offer 59 - II. 队列的最大值">剑指 Offer 59 - II. 队列的最大值
- 剑指 Offer II 041. 滑动窗口的平均值(easy)">剑指 Offer II 041. 滑动窗口的平均值(easy)
- 剑指 Offer II 043. 往完全二叉树添加节点(重点)">剑指 Offer II 043. 往完全二叉树添加节点(重点)
- 剑指 Offer II 045. 二叉树最底层最左边的值">剑指 Offer II 045. 二叉树最底层最左边的值
- 剑指 Offer II 046. 二叉树的右侧视图">剑指 Offer II 046. 二叉树的右侧视图
剑指 Offer 59 - I. 滑动窗口的最大值
总是忘记优先队列!!!!!!
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k == 0){
return {};
}
int n = nums.size();
priority_queue<pair<int, int>> q;
for (int i = 0; i < k; ++i) {
q.emplace(nums[i], i);
}
vector<int> ans = {q.top().first};
for (int i = k; i < n; ++i) {
q.emplace(nums[i], i);
while (q.top().second <= i - k) {//保证区间最大值在滑窗范围内
q.pop();
}
ans.push_back(q.top().first);
}
return ans;
}
};
单调队列
使用双端队列deque
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k == 0) return {};
int n = nums.size();
deque<int> q;//双端队列
for (int i = 0; i < k; ++i) {
while (!q.empty() && nums[i] >= nums[q.back()]) {//当数字大于尾部元素时,将尾部元素弹出,
//这样的话这个队列将会是一个从低到上的递增队列
//有点像人工优先队列
q.pop_back();
}
q.push_back(i);
}
vector<int> ans = {nums[q.front()]};
for (int i = k; i < n; ++i) {
while (!q.empty() && nums[i] >= nums[q.back()]) {
q.pop_back();
}
q.push_back(i);
while (q.front() <= i - k) {//当最大值不在滑动窗口的范围中时,弹出最大值
q.pop_front();
}
ans.push_back(nums[q.front()]);
}
return ans;
}
};
剑指 Offer 59 - II. 队列的最大值
核心思想还是维护一个从底到上递增双端队列。同时可以进行前后的插入操作
核心思想在于两个大值之间的小值根本就不会影响到最终结果,因此只需要递增的值就可以了,
这个想法非常重要,和上面一题的单调解法的思路一摸一样
class MaxQueue {
queue<int> q;
deque<int> d;//双端队列
public:
MaxQueue() {
}
int max_value() {
if (d.empty())
return -1;
return d.front();
}
void push_back(int value) {
while (!d.empty() && d.back() < value) {//维护一个递增的队列
d.pop_back();
}
d.push_back(value);
q.push(value);
}
int pop_front() {
if (q.empty())
return -1;
int ans = q.front();
if (ans == d.front()) {
d.pop_front();
}
q.pop();
return ans;
}
};
剑指 Offer II 041. 滑动窗口的平均值(easy)
- 几乎没有难点,主要是可以有优化写法
防止和溢出。 ```cpp class MovingAverage { private: double average = 0; queue
q; double size, qsize = 0; public: /* Initialize your data structure here. / MovingAverage(int size):size(size) { } double next(int val) {
if(qsize == size){ average = average - q.front()/size + val/size; q.pop(); q.push(val); } else { average = qsize/(qsize+1)*average + val/(qsize+1); q.push(val); qsize++; } return average;
} };
<a name="TPaSy"></a>
### [剑指 Offer II 042. 最近请求次数](https://leetcode-cn.com/problems/H8086Q/)(easy)
- 平平无奇
```cpp
class RecentCounter {
queue<int> q;
public:
RecentCounter() {
}
int ping(int t) {
while(!q.empty()&&q.front() < (t-3000)){
q.pop();
}
q.push(t);
return q.size();
}
};
剑指 Offer II 043. 往完全二叉树添加节点(重点)
- 需要注意队列先进出的特点
- 从左到右先进
出的时候是从左到右 ```cpp class CBTInserter { TreeNode root; queue<TreeNode> q; public: CBTInserter(TreeNode* root) {
this->root = root; q.push(root); while(!q.empty()){ TreeNode* node = q.front(); if(node->left&&node->right){ q.pop(); q.push(node->left); q.push(node->right); } else { break; } } if(q.front()->left) q.push(q.front()->left);
}
int insert(int v) {
int res = q.front()->val; if(!q.front()->left){ q.front()->left = new TreeNode(v); q.push(q.front()->left); } else if(!q.front()->right){ q.front()->right = new TreeNode(v); q.push(q.front()->right); q.pop(); } return res;
}
TreeNode* get_root() {
return root;
} };
<a name="v5Eeg"></a>
### [剑指 Offer II 044. 二叉树每层的最大值](https://leetcode-cn.com/problems/hPov7L/)
- 和二叉树的层序遍历类似
```cpp
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
if(!root) return {};
queue<TreeNode*> q;
q.push(root);
vector<int> res;
while(!q.empty()){
int n = q.size(), maxs= INT_MIN;
for(int i = 0; i < n; i++){
TreeNode* node = q.front();
q.pop();
maxs = max(maxs, node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
res.push_back(maxs);
}
return res;
}
};
剑指 Offer II 045. 二叉树最底层最左边的值
-
bfs
class Solution { public: int findBottomLeftValue(TreeNode* root) { int ret; queue<TreeNode*> q; q.push(root); while(!q.empty()){ int n = q.size(); for(int i = 0; i < n ; i++){ TreeNode* node = q.front(); q.pop(); if(i == 0) { ret = node->val; } if(node->left) q.push(node->left); if(node->right) q.push(node->right); } } return ret; } };
dfs
注意height初始值为-1,因为如果只有根节点的时候能够赋值ret
class Solution { private: int ret, height = -1; public: int findBottomLeftValue(TreeNode* root) { dfs(root, 0); return ret; } void dfs(TreeNode* root, int g){ if(!root) return; if(g > height) { ret = root->val; height = g; } dfs(root->left, g + 1); dfs(root->right, g + 1); return ; } };
剑指 Offer II 046. 二叉树的右侧视图
上一题的变种
class Solution { public: vector<int> rightSideView(TreeNode* root) { if(!root) return {}; queue<TreeNode*> q; q.push(root); vector<int> ret; while(!q.empty()){ int n = q.size(); for(int i = 0; i < n; i++){ TreeNode* node = q.front(); q.pop(); if(i == 0) { ret.push_back(node->val); } if(node->right) q.push(node->right); if(node->left) q.push(node->left); } } return ret; } };