本周通过题单上的四道题基本了解了vector ,map的用法
并利用其进行二维映射和构建链表(单向,双向)
vector 用法:
vector <char> v; // vector默认长度是0, 类型可以是c++的标准类型,也可以是自己定义的类或结构体
vector <int> v(N); // 效果类似int v[N];但是N可以是变量
vector <int> v(N, i); // 可变数组最开始有N个元素,每个元素的值是i,i可以省略不写
注意
vector <int> v(N);
vector <int> v(N, i);
在结构体中不可声明(在编译过程中无法执行)
只能在程序执行时运行。
题目描述
超市里有 n(1\le n\le10^5)n(1≤n≤105) 个寄包柜。每个寄包柜格子数量不一,第 ii 个寄包柜有 a_i(1\le a_i\le10^5)ai(1≤ai≤105) 个格子,不过我们并不知道各个 a_iai 的值。对于每个寄包柜,格子编号从 1 开始,一直到 a_iai。现在有 q(1 \le q\le10^5)q(1≤q≤105) 次操作:
1 i j k
:在第 ii 个柜子的第 jj 个格子存入物品 k(0\le k\le 10^9)k(0≤k≤109)。当 k=0k=0 时说明清空该格子。2 i j
:查询第 ii 个柜子的第 jj 个格子中的物品是什么,保证查询的柜子有存过东西。已知超市里共计不会超过 10^7107 个寄包格子,a_iai 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。
输入格式
第一行 2 个整数 nn 和 qq,寄包柜个数和询问次数。
接下来 qq 个整数,表示一次操作。
输出格式
对于查询操作时,输出答案,以换行隔开。
输入输出样例
输入 #1复制
5 4 1 3 10000 118014 1 1 1 1 2 3 10000 2 1 1输出 #1复制
118014 1
基本思路 :
首先我尝试用vector
建立结构体
struct guizi
{
vector<string> wupin;
vector<int> next;
int xuhao=0;
};
struct chaoshi
{
vector <guizi> gui;
};
并利用vector的resize和push_back
具体代码如下:
#include <bits/stdc++.h>
using namespace std;
struct guizi
{
vector<string> wupin;
vector<int> next;
int xuhao=0;
};
struct chaoshi
{
vector <guizi> gui;
};
chaoshi chao;
void hanshu2(int temp1,int temp2,string temp3)
{
chao.gui[temp1].xuhao++;
chao.gui[temp1].wupin.push_back(temp3);
chao.gui[temp1].next.push_back(temp2);
return;
}
void hanshu1(int temp1,int temp2 )
{
for(int i=chao.gui[temp1].xuhao-1;i>=0;i--)
{
if(chao.gui[temp1].next[i]==temp2)
{
cout<<chao.gui[temp1].wupin[i]<<endl;break;}
}
return;
}
int main()
{ int n,q,temp1,temp2,flag;
string temp3;
cin>>n>>q;
chao.gui.resize(n+1);
for(int i=0;i<q;i++)
{ cin>>flag;
if(flag==2)
{
cin>>temp1>>temp2;
hanshu1(temp1,temp2);
}
else
{
cin>>temp1>>temp2>>temp3;
hanshu2(temp1,temp2,temp3);
}
}
}
但是这种方法在查询第 ii 个柜子的第 jj 个格子中的物品是什么的时候
时间复杂度是O(n)
在最后一个测试点是会超时
因此使用map进行hash映射
map用法:
自动建立key - value的对应。
map<数据类型key, 数据类型value> 映射名称personal;
基本操作:插入
第一种 用insert函數插入pair
mapStudent.insert(pair<int, string>(000, "student_zero"));
第二种 用insert函数插入value_type数据
mapStudent.insert(map<int, string>::value_type(001, "student_one"));
第三种 mapStudent[123] = "student_first";
mapStudent[456] = "student_second";
关键:
第一种和第二种在效果上是完成一样的,用insert函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是不能在插入数据的,但是用数组方式就不同了,它可以覆盖以前该关键字对 应的值。
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数(1或0)
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
upper_bound() 返回键值>给定元素的第一个位置
lower_bound() 返回键值>=给定元素的第一个位
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
value_comp() 返回比较元素value的函数
AC代码如下;‘
#include<bits/stdc++.h>
using namespace std;
map <int,map<int,string>>yingshe;
int main(){
int n,q,x,y,k;
string z;
cin>>n>>q;
for(int i=1;i<=q;++i){
scanf("%d%d%d",&k,&x,&y);
if(k==1){
cin>>z;
yingshe[x][y]=z;//将z赋值给key为x(柜子号)y(格子号)
}
else{
cout<<yingshe[x][y]<<endl;//输出查找的物品
}
}
return 0;
}
题目2
题目描述
定义如下规则:
- 空串是「平衡括号序列」
- 若字符串 SS 是「平衡括号序列」,那么 \texttt{[}S\texttt][S] 和 \texttt{(}S\texttt)(S) 也都是「平衡括号序列」
- 若字符串 AA 和 BB 都是「平衡括号序列」,那么 ABAB(两字符串拼接起来)也是「平衡括号序列」。
例如,下面的字符串都是平衡括号序列:
()
,[]
,(())
,([])
,()[]
,()[()]
而以下几个则不是:
(
,[
,]
,)(
,())
,([()
现在,给定一个仅由
(
,)
,[
,]
构成的字符串 ss,请你按照如下的方式给字符串中每个字符配对:
- 从左到右扫描整个字符串。
- 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近的未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。
配对结束后,对于 ss 中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。
输入格式
输入只有一行一个字符串,表示 ss。
输出格式
输出一行一个字符串表示你的答案。
输入输出样例
输入 #1复制
([()输出 #1复制
()[]()输入 #2复制
([)输出 #2复制
()[]()说明/提示
数据规模与约定
对于全部的测试点,保证 ss 的长度不超过 100,且只含
(
,)
,[
,]
四个字符。
思路
struct XIN { int flag; char zifu; };
创建结构体XIN
flag用来判断是否配对完成
#include <bits/stdc++.h>
using namespace std;
struct XIN
{
int flag;
char zifu;
};
vector<XIN> xin;
void hanshu(int temp)
{
for(int k=temp;k>=0;k--)
{
if(xin[k].flag==1)
{
if((xin[k].zifu=='('&&xin[temp].zifu==')')||(xin[k].zifu=='['&&xin[temp].zifu==']'))
{
xin[k].flag=0;
xin[temp].flag=0;return;
}
else return;
}
}
}
int main()
{
string s;
cin>>s;
int len=s.length(),temp;
xin.resize(len);
for(int i=0;i<len;i++)
{
xin[i].zifu=s[i];
if(s[i]=='['||s[i]=='(')
xin[i].flag=1;
else {
xin[i].flag=2;temp=i;
hanshu(temp);
}
}
for(int i=0;i<len;i++)
{
if((xin[i].flag==1&&xin[i].zifu=='(')||(xin[i].flag==2&&xin[i].zifu==')'))
cout<<"()";
else if((xin[i].flag==1&&xin[i].zifu=='[')||(xin[i].flag==2&&xin[i].zifu==']'))
cout<<"[]";
else cout<<xin[i].zifu;
}
}
输入 到string中
从string【0】开始遍历
根据题目要求观察是否配对
若配对 则将其flag化为0
最后再次遍历,若flag不为0
则将该字符配对:输出“()”或“<>”
若已经配对 就原样输出。
题目3
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:\texttt{3*(5-2)+7}3*(5-2)+7 对应的后缀表达式为:\texttt{3.5.2.-*7.+@}3.5.2.-*7.+@。在该式中,
@
为表达式的结束符号。.
为操作数的结束符号。输入格式
输入一行一个字符串 ss,表示后缀表达式。
输出格式
输出一个整数,表示表达式的值。
输入输出样例
输入 #1复制
3.5.2.-*7.+@输出 #1复制
16说明/提示
数据保证,1 \leq |s| \leq 501≤∣s∣≤50,答案和计算过程中的每一个值的绝对值不超过 10^9109。
AC代码
#include <bits/stdc++.h>
using namespace std;
struct ZHAN
{
long long int data[50];
int top;
};
int main()
{ int now,ans=0;
char ch;
ZHAN zhan;
zhan.top=0;
while((ch=getchar())!='@')//限制输入格式
{
if(ch>='0'&&ch<='9') now*=10,now+=ch-'0';//将字符形式转化为数字
else if(ch=='.'){
zhan.top ++;
zhan.data[zhan.top]=now;
now=0;
}
else if(ch=='-') {
zhan.data[zhan.top-1]=zhan.data[zhan.top-1]-zhan.data[zhan.top];zhan.top=zhan.top-1;}
else if(ch=='+') {
zhan.data[zhan.top-1]=zhan.data[zhan.top-1]+zhan.data[zhan.top];zhan.top=zhan.top-1;}
else if(ch=='*') {
zhan.data[zhan.top-1]=zhan.data[zhan.top-1]*zhan.data[zhan.top];zhan.top=zhan.top-1;}
else if(ch=='/') {
zhan.data[zhan.top-1]=zhan.data[zhan.top-1]/zhan.data[zhan.top];zhan.top=zhan.top-1;}
}//加减乘除四种运算
cout<<zhan.data[1];
}
用结构体实现入栈出栈
将char转换为数字。
题目4
题目描述
一个学校里老师要将班上 NN 个同学排成一列,同学被编号为 1\sim N1∼N,他采取如下的方法:
先将 11 号同学安排进队列,这时队列中只有他一个人;
2-N2−N 号同学依次入列,编号为 ii 的同学入列方式为:老师指定编号为 ii 的同学站在编号为 1\sim(i-1)1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
从队列中去掉 M(M<N)M(M<N) 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第 11 行为一个正整数 NN,表示了有 NN 个同学。
第 2\sim N2∼N行,第 ii 行包含两个整数 k,pk,p,其中 kk 为小于 ii 的正整数,pp 为 00 或者 11。若 pp 为00,则表示将 ii 号同学插入到 kk 号同学的左边,pp 为 11 则表示插入到右边。
第 N+1N+1 行为一个正整数 MM,表示去掉的同学数目。
接下来 MM 行,每行一个正整数 xx,表示将 xx 号同学从队列中移去,如果 xx 号同学已经不在队列中则忽略这一条指令。
输出格式
11 行,包含最多 NN 个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入 #1复制
4 1 0 2 1 1 0 2 3 3输出 #1复制
2 4 1说明/提示
样例解释:
将同学 22 插入至同学 11 左边,此时队列为:
2 1
将同学 33 插入至同学 22 右边,此时队列为:
2 3 1
将同学 44 插入至同学 11 左边,此时队列为:
2 3 4 1
将同学 33 从队列中移出,此时队列为:
2 4 1
同学 33 已经不在队列中,忽略最后一条指令
最终队列:
2 4 1
数据范围
对于 20\%20% 的数据,有 1\leq N\leq 101≤N≤10;
对于 40\%40% 的数据,有 1\leq N\leq 10001≤N≤1000;
对于 100\%100% 的数据,有 1\leq N,M\leq1000001≤N,M≤100000。
思路
利用三个数组
实现双向链表
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int mx=1e5+10;
int n,m;
struct T{
int l,r; //每个同学的“左右手”
int d; //表示同学是否输出
}t[mx]={0};
void add(int i,int k,int f) //新增同学
{
if(f==1) //左
{
t[k].r=t[i].r;
t[k].l=i;
t[i].r=k;
t[t[k].r].l=k;
}
else //右
{
t[k].r=i;
t[k].l=t[i].l;
t[i].l=k;
t[t[k].l].r=k;
}
}
int main()
{
int x,k,f;
cin>>n;
t[0].r=0,t[0].l=0;
add(0,1,1);
for (int i=2;i<=n;i++)
{
cin>>x>>f;
add(x,i,f);
}
cin>>m;
while(m--)
{
cin>>x;
t[x].d=1; //将该同学标记为不输出
}
for (int i=t[0].r;i;i=t[i].r)
{
if (t[i].d==0) //输出未标记的
cout<<i<<" ";
}
return 0;
}