1、区间合并
之前网易面试的时候遇到过区间合并的问题,结果不会做,进行把y总的课的区间合并部分看了以下,简单记录以下模板,以便于后面学习使用。
主要的思路就是:
1、先对所有区间的左端点进行排序。
2、然后进行区间合并(只有三种情况)
第一种情况:当前需合并区间 和 当前维护区间没有交集。
第二种情况:当前需合并区间 和 当前维护区间有交集。
第三种情况:当前需合并区间 被 当前维护区间包含。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
int n;
void merge(vector<PII>& segs){
vector<PII> ans;
sort(segs.begin(), segs.end());
// 定义初始维护区间
int st = INT_MIN, ed = INT_MIN;
for(auto& seg : segs){
if(ed < seg.first){
// 说明当前的seg 和 当前维护的区间 没有交集
if(st != INT_MIN) ans.push_back({st, ed});
// 更新 当前维护的区间
st = seg.first;
ed = seg.second;
}else{
// 说明当前的seg 和 当前维护的区间 有交集
ed = max(ed, seg.second);
}
}
// 将最后一个维护的区间进行存储
if(st != INT_MIN) ans.push_back({st, ed});
segs = ans;
}
int main(){
cin>>n;
int l, r;
vector<PII> segs;
while(n--){
cin>>l>>r;
segs.push_back({l, r});
}// end while
merge(segs);
cout<<segs.size()<<endl;
return 0;
}
2、单调栈
最近做leetcode遇到了一些单调栈的问题,所以先简单记录一下模板,后续在进行补充:
#include<bits/stdc++.h>
using namespace std;
/*
例如涉及一个题目:
找到当前数组中
1、比当前数字小的
2、并且在当前数字左边的
3、离当前数字最近
的对应数字的下标(没找到用-1代替)
思路:就是维护一个单调递增的栈
*/
int main(){
// 答案为:[-1, 0, -1, -1, 3, 4, 3]
vector<int> nums = {4, 5, 2, 1, 7, 10, 3};
stack<int> stk;
vector<int> ans;
int size = nums.size();
for(int i=0; i<size; i++){
int num = nums[i];
while(!stk.empty() and num <= nums[stk.top()]){
stk.pop();
}
int index = stk.empty() ? -1 : stk.top();
ans.push_back(index);
stk.push(i);
}
for(auto& num : ans) cout<<num<<" ";
return 0;
}
/*
模板就是:
// 有些题目是进行倒叙的遍历
for(int i=0; i<size; i++){
while(!stk.empty() and check()){
// 具体的操作
}
// 具体的操作
stk.push(i); // 入栈
}
*/
3、 滑动窗口
滑动窗口的题在找实习面试的时候暂时还没有遇到过,自己做了之后主要总结为:
1、在求子串问题时进行出现。
2、在出现数字全为正数的时候会出现比较多,出现负数可以考虑前缀和。
/*
只是简单写一下模板
*/
int size = s.size();
int l=0, r=0;
// 我习惯维护一个闭区间 [l, r]
while(r < size){
while(l<r and check()){
// 具体的操作 目的是:移动左边界 l++
}
// 具体的操作
r++; // 在最后进行r++ 移动右边界。
}
4、前缀和
前缀和还没有进行很好的总结过,先记录一下模板,后续有总结再进行补充:
/*
只对前缀和 数组的生成 进行模板
prefixSum[i] 表示前i个数字的和
*/
int size = nums.size();
vector<int> prefixSum(size+1, 0);
for(int i=1; i<=size; i++){
prefixSum[i] = prefixSum[i-1] + nums[i-1];
}