算法题中 涉及链表 要用数组模拟 不然超时
单链表 head(清楚头指针的含义), e[], ne[], idx(只有插入操作会让idx++)
五个操作 初始化+ 头插头删+ k下标插 k下标删
head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;
初始化!!!!!!!!!!!!
void init()
{
head = -1;
idx = 0;
}
在链表头插入一个数a 先右后左
void insert(int a)
{
e[idx] = a;
ne[idx] = head;
head = idx ++ ;
}
将头结点删除,需要保证头结点存在
void remove()
{
head = ne[head];
}
将x插到下标是k的点后面 先右后左
void add(int k, int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx ++ ;
}
将下标是k的点【后面】的点删掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void remove(int k)
{
ne[k] = ne[ne[k]];
}
#include<iostream>
#include<cstring>
using namespace std;
const int N=100000;
int head,idx,e[N],ne[N];
void init(){
head=-1;
idx=0;
}
void head_insert(int x){
e[idx]=x;
ne[idx]=head;
head=idx;
idx++;
}
void k_insert(int k,int x){
e[idx]=x;
ne[idx]=ne[k];
ne[k]=idx;
idx++;
}
void k_delete(int k){
ne[k]=ne[ne[k]];
}
int main(){
init();
int n;
cin>>n;
while(n--){
string a;
cin>>a;
if(a=="H"){
int x;
cin>>x;
head_insert(x);
}
if(a=="I"){
int k,x;
cin>>k>>x;
k_insert(k-1,x);
}
if(a=="D"){
int k;
cin>>k;
if(k==0) head=ne[head];
else k_delete(k-1);
}
}
for(int i=head;i!=-1;i=ne[i]){ 遍历的操作
cout<<e[i]<<" ";
}
}
双链表 0是左端点,1是右端点
初始化 右插(同时实现左插)
// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;
// 初始化
void init()
{
//0是左端点,1是右端点
r[0] = 1, l[1] = 0;
idx = 2;
}
在节点a的右边插入一个数x 先新后右最后左 右插insert(a,x) 左插insert(l[a],x)
void insert(int a, int x)
{
e[idx] = x;
l[idx] = a, r[idx] = r[a]; 先新
l[r[a]] = idx;后右
r[a] = idx ++ ; 最后左
}
删除下标为a的结点
void remove(int a)
{
l[r[a]] = l[a];
r[l[a]] = r[a];
}
单调栈O(N) 找出每个数左边离它最近的比它大/小的数
找左边邻近小
#include<bits/stdc++.h>
using namespace std;
stack<int> stk;
int main(){
int n; cin>>n;
while(n--){
int x;
scanf("%d",&x);
while(!stk.empty()&&x<=stk.top()) stk.pop();栈里比我大的都弹出 他们因为比我小不会再被输出
if(!stk.empty()) cout<<stk.top()<<" "; 栈里余下的第一个即为我的左邻近小
else cout<<"-1 "; 栈空说明没有我的左邻近小
stk.push(x);
}
}
找右邻近大 可以逆着看 相当于找左邻近大 但是输出要逆序输出
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int a[N];
stack<int> stk;
stack<int> answer; 逆序输出用
int main(){
int n; cin>>n;
for(int i=0;i<n;i++){
scanf("%d,",&a[i]);
}
for(int i=n-1;i>=0;i--){ 逆着看
while(!stk.empty()&&a[i]>=stk.top()) stk.pop(); 找大 则栈里小的出去
if(!stk.empty()) answer.push(stk.top());
else answer.push(-1);
stk.push(a[i]);
}
while(!answer.empty()){ 逆序输出
cout<<answer.top()<<" ";
answer.pop();
}
}
单调队列 求滑动窗口中的最大最小值
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int a[N];
int main(){
deque<int> Q; 因为头尾都会删 所以要用双端队列 队列中存放下标
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
输出窗口里的最小值
for(int i=0;i<n;i++){ 遍历数组
if(!Q.empty()&&Q.front()<i-k+1) Q.pop_front(); 保证队列在当前下表的感受野内
以下操作保证队列单调
while(!Q.empty()&&a[i]<=a[Q.back()]) Q.pop_back(); 队列里比我大的都弹出
Q.push_back(i); 我进去
if(i>=k-1) cout<<a[Q.front()]<<" "; 不断输出队首 因为单调,队首总是最小值
}
cout<<endl;
Q.clear(); 清零
输出窗口里的最大值
for(int i=0;i<n;i++){
if(!Q.empty()&&Q.front()<i-k+1) Q.pop_front();
while(!Q.empty()&&a[i]>=a[Q.back()]) Q.pop_back();
Q.push_back(i);
if(i>=k-1) cout<<a[Q.front()]<<" ";
}
}