目录
L4-202 二叉搜索树的2层结点统计 - 构建二叉搜索树板子
L2-041 插松枝 - 栈 + 队列 + 模拟
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
vector<int> res;
int n,m,k,pre;
int main()
{
stack<int> stk;
queue<int> q;
int cnt=0; //cnt根松枝已经有归属
cin>>n>>m>>k;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
q.push(x);
}
while(1)
{
if(cnt==n&&stk.empty()) break; //如果所有松枝都有归属 且 盒子里无松枝
res.clear();
pre=110;
while(!stk.empty()&&stk.top()<=pre)
{
int x=stk.top();
if(res.size()>=k) break;
pre=x;
cnt++; //该松枝已有归属
res.push_back(x);
stk.pop();
}
while(!q.empty()) //在推进器取松针
{
if(res.size()<k) //如果松枝未插满
{
if(q.front()<=pre) //如果松针长度≤上一根长度
{
pre=q.front();
cnt++;
res.push_back(pre);
q.pop();
}else if(stk.size()<m) //如果不满足要求 且小盒子还能放 放小盒子
{
stk.push(q.front());
q.pop();
}else break;
}else break;
}
for(int i=0;i<res.size();i++)
{
if(i!=0) cout<<" ";
cout<<res[i];
}
cout<<endl;
}
}
L4-205 浪漫侧影 - 中后序建树 + bfs层序遍历
思路:
第一步:建树
- left存左孩子 right存右孩子
- idx存节点x在中序遍历的下标
- 通过dfs建树,刚开始后序和中序遍历的范围均为[0~n-1]
- 后序遍历范围【l1,r1】 中序遍历范围【l2,r2】
- 每棵子树的根节点为r1
- k=idx[root]找出该根节点在中序遍历的下标
- 递归分别建立左子树和右子树
第二步:bfs层序遍历
- 将根节点入队进行bfs
- 先用len记录每一层节点个数q.size(),循环len个节点
- lst记录左侧倒影(即每一层的第一个节点) rst记录右侧倒影(即每一层最后一个节点)
- 如果该节点有左右孩子,则入队
#include <bits/stdc++.h>
using namespace std;
const int N=30;
int n,cnt;
int last[N],mid[N];
unordered_map<int,int> leftt,rightt; //left[i]=j i的左孩子是j
unordered_map<int,int> idx; //idx[x]=i 节点x在中序遍历中下标为i
vector<int> lst,rst;
int dfs(int lastt[],int midd[],int l1,int r1,int l2,int r2)
{
if(l1>r1) return 0; //没有节点
int root=lastt[r1]; //当前子树的根节点为当前范围内的最后一个节点
int k=idx[root]; //当前根节点在中序遍历的下标
leftt[root]=dfs(lastt,midd,l1,l1+k-l2-1,l2,k-1);
rightt[root]=dfs(lastt,midd,l1+k-l2,r1-1,k+1,r2);
return root;
}
void bfs(int rt)
{
queue<int> q;
q.push(rt);
while(!q.empty())
{
int len=q.size();
for(int i=0;i<len;i++)
{
auto t=q.front();
q.pop();
if(i==0) lst.push_back(t);
if(i==len-1) rst.push_back(t);
if(leftt[t]) q.push(leftt[t]);
if(rightt[t]) q.push(rightt[t]);
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>mid[i];
idx[mid[i]]=i;
}
for(int i=1;i<=n;i++) cin>>last[i];
int root=dfs(last,mid,1,n,1,n); //建树
bfs(root);
cout<<"R: ";
for(int i=0;i<rst.size();i++)
{
if(i!=0) cout<<" ";
cout<<rst[i];
}
cout<<endl;
cout<<"L: ";
for(int i=0;i<lst.size();i++)
{
if(i!=0) cout<<" ";
cout<<lst[i];
}
}
L4-204 盲盒包装流水线 - 栈模拟
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,s;
cin>>n>>s;
int a[n];
stack<int> stk;
map<int,int> mp;
for(int i=0;i<n;i++) cin>>a[i];
int k=n/s;
int pre=0;
while(k--)
{
for(int i=0;i<s;i++)
{
int x;
cin>>x;
stk.push(x);
}
int cnt=s;
for(int i=pre;cnt>0;i++)
{
mp[a[i]]=stk.top();
stk.pop();
cnt--;
}
pre+=s;
}
int q;
cin>>q;
while(q--)
{
int tt;
cin>>tt;
if(!mp.count(tt)) cout<<"Wrong Number"<<endl;
else cout<<mp[tt]<<endl;
}
}
L4-203 三足鼎立 - 二分
思路:
用暴力肯定会超时,因此先求出每个a[i]的合法范围
【任意两两实力之和均大于第三国】已知a[i]和x,则需要选择的第三国v实力应满足
我们可以先进行排序,再遍历每一个a[i],然后通过二分在它的后方统计在合法数据个数
定义
![]()
- 先在【i+1,n-1】范围内找大于minx的最小数,记录下标为ll
- 再在【i+1,n-1】范围内找小于maxx的最大数,记录下标为rr
最后如果a[ll]、a[rr]也在合法范围内,则答案res+=rr-ll+1
#include <bits/stdc++.h>
#define PII pair<int,int>
#define pb push_back
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
signed main()
{
int n,x;
int res=0;
cin>>n>>x;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
for(int i=0;i<n-1;i++)
{
int maxx=x+a[i];
int minx=fabs(x-a[i]);
int l=i+1,r=n-1;
while(l<r) //先找到大于mi的最小值
{
int mid=l+r>>1;
if(a[mid]>minx) r=mid;
else l=mid+1;
}
int ll=l;
l=i+1,r=n-1;
while(l<r) //再找到小于mx的最大值
{
int mid=l+r+1>>1;
if(a[mid]<maxx) l=mid;
else r=mid-1;
}
int rr=r;
//cout<<a[i]<<" "<<minx<<" "<<maxx<<" "<<ll<<" "<<rr<<endl;
if(a[ll]<maxx&&a[ll]>minx&&a[rr]>minx&&a[rr]<maxx) res+=rr-ll+1;
}
cout<<res;
}
L4-202 二叉搜索树的2层结点统计 - 构建二叉搜索树板子
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,cnt;
int a[N],res[N]; //res记为每层节点个数
int l[N],r[N];
int maxd;
void insert(int &u,int x) //加引用为了修改之前l[]r[]的值 不然需要区分左孩子和右孩子
{
if(u==0)
{
u=++cnt;
a[u]=x;
}
else if(x<=a[u]) insert(l[u],x);
else insert(r[u],x);
}
void dfs(int u,int d)
{
if(!u) return;
res[d]++;
maxd=max(maxd,d);
dfs(l[u],d+1);
dfs(r[u],d+1);
}
int main()
{
cin>>n;
int root=0;
for(int i=0;i<n;i++) //每次插入节点时 遍历整个树
{
int x;
cin>>x;
insert(root,x);
}
dfs(root,0);
int n1=res[maxd-1];
int n2=res[maxd];
cout<<n1+n2;
}
L4-201 出栈序列的合法性 - 栈模拟
思路:
- 对与每个给定序列,一个一个遍历a[i]
- 因为栈按1、2、3……的顺序进栈,因此设x为进栈元素,初始为1
- 如果a[i]!=x,则持续入栈(如果栈满都无法使x==a[i],则直接false)
- 为什么是stk.size()>=m 就退出?为什么加=号?
- 答:因为得到序列时,值需要进栈再出栈,如果你所需的值进栈前栈都满了,说明无法得到合法序列
- 如果a[i]==x,则x++
- 如果栈非空且栈顶元素==a[i],则弹出栈顶,继续下一个a[i]
- 遍历完所有a[i],如果没有出现false情况则输出true
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m,n,k;
cin>>m>>n>>k;
while(k--)
{
int a[n];
bool f=true;
for(int i=0;i<n;i++) cin>>a[i];
stack<int> stk;
int x=1;
for(int i=0;i<n;i++)
{
if(!stk.empty()&&stk.top()==a[i]) //如果栈顶元素直接符合所需 直接返回
{
stk.pop();
continue;
}
while(x!=a[i]) //如果不是所需 则把数往栈里按 注意:如果x==a[i]是不发生循环的
{
stk.push(x);
if(stk.size()>=m) //如果栈已满都没有得到所需数字 说明无法得到
{
f=false;
break;
}
x++;
}
if(!f) break;
if(x==a[i]) x++;
}
if(f) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}