栈(stack):一种特殊线性数据结构,只允许在栈的一端插入或删除元素【栈顶】,另一端【栈底】
重要性质:先进后出,类似于往子弹夹装子弹然后发弹
递归:函数调用自身,一般解决有重复子问题的问题。
边界条件:什么情况下,函数不应该再继续调用自身
队列和栈
队列:
int q[1000], l = 0, r = 0; // 初始化
q[r++] = x; // 入队
int now = q[l]; // 获取队首
l++; // 出队
q[r++] = y;
printf("%d\n", q[l++]); // 获取队首同时出队
if (l < r) { // 判断是否为空
printf("not empty\n");
}
栈:
int s[100], top = -1;
s[++top] = x; // 入栈
int now = s[top]; // 获取栈顶元素
top--; // 出栈
s[++top] = y;
printf("%d\n", s[top--]); // 获取栈顶同时出栈
if (top >= 0) { // 栈不为空
printf("not empty\n");
}
循环队列:
const int size = 100000;
int q[size], l = 0, r = 0; // 初始化
q[r] = x; r = (r + 1) % size; // 入队
int now = q[l]; // 获取队首
l = (l + 1) % size; // 出队
q[r] = y; r = (r + 1) % size;
printf("%d\n", q[l]); l = (l + 1) % size; // 获取队首同时出队
if (l != r) { // 判断是否为空
printf("not empty\n");
}
字符串栈:
char s[100][1000], top = -1;
scanf("%s", s[++top]); // 入栈
char t[1000];
strcpy(t, s[top]); // 获取栈顶元素
top--; // 出栈
strcpy(s[++top], t);
printf("%s\n", s[top--]); // 获取栈顶同时出栈
if (top >= 0) { // 栈不为空
printf("not empty\n");
}
报数(利用约瑟夫环)
有 n个小朋友做游戏,他们的编号分别是 1,2,3...n。他们按照编号从小到大依次顺时针围成一个圆圈,从第一个小朋友开始从 1 报数,依次按照顺时针方向报数(加一),报 m 的人会离开队伍,然后下一个小朋友会继续从 1 开始报数,直到只剩一个小朋友为止。
输入格式
第一行输入两个整数,n,m。( 10001≤n,m≤1000)
输出格式
输出最后一个小朋友的编号,占一行。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
10 5
样例输出
3
#include<stdio.h>
int ysfhuan(int n,int m, int i){
if(i==1){
return (m-1+n)%n;
}
return (ysfhuan(n-1,m,i-1)+m)%n;
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
printf("%d",ysfhuan(n,m,n)+1);
return 0;
}
2.
有一种酒桌游戏叫做“敲7”,规则是从一个人开始,说出任意数字,其他人会顺序往后报,如果一个数字包含 7,或者是 7 的倍数,那么需要敲打杯子或盘子,不能说出。
现在 n 个人围坐在一个圆桌周围,他们编号从 1 到 n 顺时针排列。从某一人开始报出一个数字,其他人会按照顺时针方向顺序往后报(加一),如果某个人的数字包含 7,或者是 7 的倍数,那么他将退出游戏,下一个人继续接着报,直到剩一个人为止。
输入格式
第一行输入三个整数,n,m,t。n 代表总人数,m 代表从第 m 个人开始报数,他报出的数字是 t。(1≤m≤n≤1000,1≤t≤100)
接下来的 n 行,每一行输入一个字符串,代表这 n 个人的名字,字符串的长度不超过 20。
输出格式
输出剩下的那个人的名字,占一行。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
-
5 3 20
-
donglali
-
nanlali
-
xilali
-
beilali
-
chuanpu
样例输出
chuanpu
#include<stdio.h>
const int L=1000;
int main(){
int n,m,t;
int q[1000];
scanf("%d %d %d",&n, &m, &t);
char a[1000][21];
int r,l;
for(int i=1;i<=n;i++){
scanf("%s",&a[i]);
}
for(int i=m;i<=n;i++){//入队
q[r++]=i;
}
for(int i=1;i<m;i++){
q[r++]=i;
}
while(n>1){
int now=q[l++];//队首指针l
l%=L;
if(t%7 !=0 && t%10!=7 && t/10%10!=7 && t/100%10 !=7){//7的倍数不行
q[r++] =now;
r%=L;
} else{
n--;
}
t++;
}
printf("%s\n",a[q[l]]);
return 0;
}
3.计蒜客 – 快速匹配
问题描述
蒜头君在纸上写了一个串,只包含’(‘和’)’。一个’(‘能唯一匹配一个’)’,但是一个匹配的’(‘必须出现在’)’之前。请判断蒜头君写的字符串能否括号完全匹配,如果能,输出配对的括号的位置(匹配的括号不可以交叉,只能嵌套)。
输入格式
一行输入一个字符串只含有’(‘和’)’,输入的字符串长度不大于50000。
输出格式
如果输入括号不能匹配,输出一行”No”,否则输出一行”Yes”,接下里若干行每行输出 2个整数,用空格隔开,表示所有匹配对的括号的位置(下标从 1 开始)。你可以按照任意顺序输出。 本题答案不唯一,符合要求的答案均正确
样例输入
()()
1
样例输出
Yes
1 2
3 4
1
2
3
代码如下
#include<stdio.h>
int main(){
int c[50000], top; // 存储左括号的位置的数组和栈顶指针
char s[50001]; // 输入的字符串
int zuo[50000], you[50000], lc, flag=1; // 记录左右括号匹配的数组和计数器及标记
scanf("%s",s);
// 遍历输入的字符串
for(int i=0; s[i]; i++){
if(s[i] == '(')
c[top++] = i; // 如果是左括号,将其位置压入栈中
else{
if(top == 0){
flag = 0; // 如果栈为空,说明匹配失败
break;
}
// 弹出栈顶的左括号位置,并记录匹配的括号对位置
zuo[lc] = c[--top];
you[lc++] = i;
}
}
if(top != 0)
flag = 0; // 如果栈非空,说明匹配失败
puts(flag ? "Yes" : "No"); // 输出匹配结果
if(flag){
// 输出匹配的括号对位置
for(int i=0; i<lc; i++)
printf("%d %d\n", zuo[i]+1, you[i]+1);
}
return 0;
}
4.计蒜客 – 网页跳转
题目要求:
蒜头君每天都在用一款名为“蒜厂浏览器”的软件。在这个浏览器中,一共三种操作:打开页面、回退和前进。它们的功能如下:
打开页面:在地址栏中输入网址,并跳转到网址对应的页面;
回退:返回到上一次访问的页面;
前进:返回到上次回退前的页面,如果上一次操作是打开页面,那么将无法前进。
现在,蒜头君打开浏览器,进行了一系列操作,你需要输出他每次操作后所在页面的网址。
输入格式
第一行输入一个整数n(0<n≤100000),表示蒜头君的操作次数。
接下来一共 n 行,每行首先输入一个字符串,如果是VISIT,后面接着输入一个不含有空格和换行的网址(网址长度小于100100),表示蒜头君在浏览器地址栏中输入的网址;如果是BACK,表示蒜头君点击了回退按钮;如果是FORWARD,表示蒜头君点击了前进按钮。
输出格式
对于每次操作,如果蒜头君能操作成功,输出蒜头君操作之后的网址,否则输出Ignore。假设蒜头君输入的所有网址都是合法的。
样例输入
10
VISIT https://www.jisuanke.com/course/476
VISIT https://www.taobao.com/
BACK
BACK
FORWARD
FORWARD
BACK
VISIT https://www.jisuanke.com/course/429
FORWARD
BACK
样例输出
https://www.jisuanke.com/course/476
https://www.taobao.com/
https://www.jisuanke.com/course/476
Ignore
https://www.taobao.com/
Ignore
https://www.jisuanke.com/course/476
https://www.jisuanke.com/course/429
Ignore
https://www.jisuanke.com/course/476
代码如下
#include <stdio.h>
#include <string.h>
int main()
{
char http[100010][105];
int n, f, top = -1, l = -1; // n为指令个数,f代表指令执行是否成功,top为栈顶指针,l为最后访问过的网页的索引
char s[105]; // 存储指令字符串的数组
scanf("%d", &n); // 输入指令个数
while (n--)
{
scanf("%s", s); // 输入指令字符串
if (s[0] == 'V') // 如果指令是“V”(Visit),表示访问网页
{
scanf("%s", http[++top]); // 输入要访问的网页,并存储到历史记录数组中
l = top; // 更新最后访问网页的索引
f = 1; // 将指令执行状态设置为成功
}
if (s[0] == 'B') // 如果指令是“B”(Back),表示返回上一页
{
if (top <= 0)
f = 0; // 如果没有上一页可返回,将指令执行状态设置为失败
else
{
top--; // 栈顶指针减1,表示返回上一页
f = 1; // 将指令执行状态设置为成功
}
}
if (s[0] == 'F') // 如果指令是“F”(Forward),表示前进到下一页
{
if (top < l) // 如果还有下一页可前进
{
top++; // 栈顶指针加1,表示前进到下一页
f = 1; // 将指令执行状态设置为成功
}
else
f = 0; // 如果没有下一页可前进,将指令执行状态设置为失败
}
if (f)
printf("%s\n", http[top]); // 如果指令执行成功,则输出当前访问的网页
else
printf("Ignore\n"); // 如果指令执行失败,则输出忽略
}
return 0;
}