【PTA-训练day29】L4-205 浪漫侧影 + L4-204 盲盒包装流水线 + L4-203 三足鼎立 + L4-202 二叉搜索树的2层结点统计 + L4-201 出栈序列的合法性

目录

L2-041 插松枝 - 栈 + 队列 + 模拟

L4-205 浪漫侧影 - 中后序建树 + bfs层序遍历

L4-204 盲盒包装流水线 - 栈模拟

L4-203 三足鼎立 - 二分

L4-202 二叉搜索树的2层结点统计 - 构建二叉搜索树板子

L4-201 出栈序列的合法性 - 栈模拟


L2-041 插松枝 - 栈 + 队列 + 模拟

PTA | 程序设计类实验辅助教学平台

#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实力应满足

                ​​​​​​​        \left | a[i]-x \right |<v<a[i]+x

我们可以先进行排序,再遍历每一个a[i],然后通过二分在它的后方统计在合法数据个数

定义  maxx=a[i]+x     minx=\left | a[i]-x\right |

  • 先在【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;
    }
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值