抱佛脚还得看我
抱着复习和避免oj网站进不去的目的,
临时兴起汇总一下OJ的拓展习题,可是时间不大够了(明天就考试T.T)
先这样吧,有空在更新(画大饼也得看我)
目录
拓展习题1
字符串去重
Description
一个完全由小写字母组成的长度为n的字符串,现在要求你去除所有重复的字母,并将剩下的字母按从小到大的次序输出。 如输入baaadccaab,输出abcd。
输入格式
第一行一个整数n,表示字符串长度(0<=n<=100000)。 第二行一个字符串。输出格式
去除所有重复的字母,并将剩下的字母按ASCII码从小到大的次序输出。输入样例
10 baaadccaab输出样例
abcd
代码如下:
#include <iostream>
using namespace std;
int book[30];//标记出现过的字母
char s[100000];
int main()
{
int n;
cin>>n;
cin>>s;
for(int i=0;i<n;i++)
{
book[s[i]-'a']=1;//换为整形,出现过就标记
}
for(int i=0;i<26;i++)//从小到大排序
{
if(book[i]==1)
cout<<(char)(i+'a');
}
}
统计不同数字的个数(升级版)
Description
由键盘输入n个整数,统计不同数字的个数(0<=n<=200000)。 PS:此题目和1040仅数据规模不同。但如果使用如下O(n2)级别的算法必然会超时。 int main() { int a[21],i,c=0,b,j; for(i=1;i<=20;i++) { cin>>b; for(j=1;j<=c;j++) { if(b==a[j]) { break; } } if(j>c) { a[c+1]=b; c++; } } cout<<c; return 0; }
输入格式
第一行一个整数n(0<=n<=200000)。 第二行n个整数a1,a2......an,(0<=ai<=200000)。输出格式
仅一行,不同数字的个数。输入样例
20 70 5 14 22 19 2 99 67 13 66 5 93 44 38 22 11 39 22 33 11输出样例
16提示
如何快速判断某个数字是否在之前出现过? 因为题目告知ai的范围,所以可以开一个bool数组记录数字是否出现(C语言用整型数组)。 例如a[1]=35,设定t[a[1]]=1,即t[35]变为1,。 这样当需要“判断某个数字是否在之前出现过”时,利用数组随机访问的特点可以O(1)的时间得到结果。
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
long long v[200005]={0};
int main()
{
ios::sync_with_stdio(false);
int n,m,ans=0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>m;
if(!v[m])
ans++;
v[m]=1;
}
cout<<ans;
}
前缀和
Description
前缀和是一种重要的预处理方法,能极大地降低查询序列区间和的时间复杂度。 现在一个序列中有n个整数,下标从1....n。 有m个查询,每个查询给出一个区间的左右端点下标,请输出这个区间所有数据的和。 注意当题目输入输出数据量比较大时,用cin和cout速度会比较慢,容易超时。解决方法: (1)用scanf和printf替换 (2)main函数第一条语句加上std::ios::sync_with_stdio(false); 关闭同步会使cin cout速度加快。
输入格式
第一行一个整数n。(1<=n<=100000) 第二行n个整数,用空格分隔,int范围。 第三行一个整数m。(1<=m<=100000) 下面m行每行两个整数L,R。(1<=L<=R<=n)输出格式
输出共m行,每行一个整数为对应区间[L,R]的序列和。 注意序列和的数据范围可能超出int范围。输入样例
5 3 -8 4 5 1 4 3 3 1 1 2 4 1 3输出样例
4 3 1 -1提示
在读入数据后,用一个sum数组来记录从第1个元素到第i个元素的和,for(i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; 这样区间[L,R]的和可以用sum[R]-sum[L-1]得到。
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
long long a[100000],sum[100000]={0};
int main()
{
ios::sync_with_stdio(false);
int n,m,l,r;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
cin>>m;
while(m--)
{
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
}
差值最大
Description
一个长度为N的整数序列,找出两个数x和y使x-y的值最大。 要求在序列中x必须在y的右侧。
输入格式
第一行是一个正整数N,表示了序列的长度(0<=N<=200000)。 第二行包含N个绝对值不大于10000的整数ai。输出格式
一个整数,为最大的差值。数据确保结果在类型int范围内。输入样例
7 4 -4 3 -1 2 -4 3输出样例
7
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n,y=0,maxn=0;
cin>>n;
for(int i=0;i<n;i++)
{
int a;
cin>>a;
maxn=max(maxn,a-y);//减去数值最小的数,找到最大差值
y=min(y,a);//y在左侧
}
cout<<maxn;
}
最大子段和
Description
一个整数序列,选出其中连续且非空的一段使得这段和最大。注意当题目要求输入输出的数据量很大时,尽量使用scanf和printf。 c++提供的cin和cout速度比较慢,有可能在读取数据和输出数据时导致超时。
输入格式
第一行是一个正整数N,表示了序列的长度(0=<N<=200000)。 第二行包含N个绝对值不大于10000的整数ai。输出格式
一个整数,为最大的子段和。子段的最小长度为1。数据确保结果在类型int范围内。输入样例
7 2 -4 3 -1 2 -4 3输出样例
4提示
【样例说明】 2,-4,3,-1,2,-4,3中,最大的子段和为4,该子段为第三元素至第五元素,即3,-1,2。
#include <iostream>
#include <algorithm>
using namespace std;
int maxn=-200000,n,minn=200000;
int main()
{
scanf("%d",&n);
int a[n],s[n]={0};
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;i++)
{
minn=min(minn,s[i]);
maxn=max(maxn,s[i]-minn);//最大子段和为前缀和-最小前缀和
}
printf("%d",maxn);
return 0;
cout<<maxn;
}
拓展习题2
后缀表达式
Description
人最熟悉的是中缀表达式,但计算机比较难处理中缀表达式,所以往往将中缀表达式改为后缀表达式。 后缀表达式,又称逆波兰式。现在从键盘读入一个后缀表达式,只含有0-9组成的运算数及加(+)、减(—)、乘(*)、除(/)四种运算符。 每个运算数之间用一个空格隔开,题目所使用的运算数均小于10,并确保所给的表达式合法。以@作为结束标志。
输入格式
一个后缀表达式。输出格式
表达式结果。输入样例
6 9 4 3 +*-@输出样例
-57
#include<iostream>
#include<stack>
using namespace std;
int main()
{
stack<int>S;//定义一个栈
int a,b,c,ch;
while((ch=getchar())!='@')//输入数据
{
if(ch<='9'&&ch>='0')//挑出数字
S.push(ch-48);//字符型变整型并入栈
else if(ch!=' ')
{
a=S.top();//存起来方便计算
S.pop();
b=S.top();
S.pop();
switch(ch)//符号的判断
{
case '+':c=a+b;break;
case '-':c=b-a;break;//注意进出栈的顺序(a和b)
case '*':c=a*b;break;
case '/':c=b/a;break;//注意进出栈的顺序(a和b)
default :break;
}
S.push(c);//存入栈中
}
}
cout<<S.top();//做完计算后输出
}
出栈序列合法性判定
Description
每年期末考试必考题目。 一个栈的进栈序列是a、b、c、d、e,则可能的出栈序列是( )。 A.abecd B.decba C.dceab D.cabde 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。 假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列, 但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
输入格式
第一行一个整数n,表示输入序列的长度。(1<=n<=10000) 第二行n个整数,表示栈的压入顺序。 第三行n个整数,表示栈的出栈顺序。输出格式
如果是弹出序列,输出yes,否则输出no。输入样例
5 1 2 3 8 6 8 6 3 2 1输出样例
yes
出栈序列
Description
一种简洁的栈定义方法如下 int st[1000],top=0;//以top作为栈顶指针,top==0为空栈 st[top++]=x;//把x入栈,栈顶指针+1 top--;//出栈 现在有一个1-n的排列,入栈序列已知,请给出字典序最大的出栈序列。
输入格式
第一行一个整数n。(1<=n<=100) 第二行n个整数,数据确保为1-n的排列。输出格式
输出n个整数,既字典序最大的出栈序列。输入样例
5 1 2 4 5 3输出样例
5 4 3 2 1
这道题小测考过
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int st[105],top=0;
int n,a[105];
cin>>n;
for(int j=0;j<n;j++)
{
cin>>a[j];
}
int i=0,ma,k;
while(i<n||top!=0)
{
if(top==0)//栈空先入栈
{
st[top++]=a[i++];
}
else
{
ma=st[top-1];//取栈顶
k=0;
for(int j=i;j<n;j++)
{
if(a[j]>ma)//看后面是否要出栈,此时字典序大
{
ma=a[j];//ma记录最大的数
k=j;
}
}
if(k!=0)//如果还没入栈的数比栈顶更大,则更新栈
{
for(int j=i;j<=k;j++)
{
st[top++]=a[j];//最大值及其前面的数一个个进栈,为了输出最大字典数
}
i=k+1;//更新i,可判断是否还有数没进来
}
cout<<st[--top]<<" ";
}
}
return 0;
}
平分物品
Description
网易2021校招笔试-文本挖掘算法工程师(提前批)第一题 现在有n个物品,每一个物品都有一个价值,现在想将这些物品分给两个人, 要求这两个人每一个人分到的物品的价值总和相同(个数可以不同,总价值相同即可, 剩下的物品就需要扔掉,现在想知道最少需要扔多少价值的物品才能满足要求分给两个人。 要求:时间复杂度O(3^n),空间复杂度O(n)
输入格式
第一行输入一个整数 T,代表有 T 组测试数据。 对于每一组测试数据,一行输入一个整数 n ,代表物品的个数。 接下来 n 个数,a[i] 代表每一个物品的价值。 1<= T <= 10 1 <= n <= 15 1 <= a[i] <= 100000输出格式
对于每一组测试数据,输出一个答案代表最少需要扔的价值。 多组数据需要换行。 样例解释,扔掉第三个和第四个物品,然后将第一个物品和第五个物品给第一个人, 第二个物品给第二个人,每一个人分到的价值为60,扔掉的价值为20。输入样例
1 5 30 60 5 15 30输出样例
20提示
注意观察题目要求,估算出需要使用何种复杂度算法。 此题目n很小,用3的n次幂这种指数级复杂度可解,可使用基于指数型枚举的深度搜索dfs。 枚举时每个物品都有三种选择,给A,给B,都不给
迷宫问题2
Description
迷宫是一个n*m的矩阵,玩家需要迷宫入口(坐标1,1)出发,寻找路径走到出口(n,m)。 请判断玩家能否从迷宫中走出,如果能走出迷宫输出,输出最短的路径长度,否则输出-1。正在上传…重新上传取消
输入格式
第一行两个整数n和m,代表n行m列。(1<=n,m<=10) 下面n行每行m个字符,0代表可以通行,1代表不可以通行。输出格式
如果能从迷宫走出,输出最短的路径长度,否则输出-1。输入样例
8 8 00100010 00100010 00001100 01110000 00010000 01000100 01110110 00001000输出样例
16
拓展习题3
最长单词
Description
一个以‘.’结尾的简单英文句子,单词之间用空格分隔,没有缩写形式和其它特殊形式。
输入格式
一个以‘.’结尾的简单英文句子(长度不超过500),单词之间用空格分隔,没有缩写形式和其它特殊形式。输出格式
该句子中最长的单词。如果多于一个,则输出第一个。输入样例
I am a student of Peking University.输出样例
University提示
注意字符"."不属于单词。
偏爱字母
Description
美团2021校招笔试-编程题(通用编程试题,第8场) 小美喜欢字母E,讨厌字母F。在小美生日时,小团送了小美一个仅包含字母E和F的字符串, 小美想从中选出一个包含字母E数量与字母F数量之差最大的子串。 *子串:从字符串前面连续删去若干个字符,从后面连续删去若干个字符剩下的字符串(也可以一个都不删), 例如abcab是fabcab的子串,而不是abcad的子串。 我们将空串看作所有字符串的子串。
输入格式
第一行一个正整数n表示字符串的长度。 第二行长度为n,且仅包含大写字母’E’,’F’的字符串(不含引号)输出格式
输出一个整数,表示最大的差值输入样例
5 EFEEF输出样例
2提示
解题建议:转化数据形式,把E看成1,把F看成-1。算法复杂度为O(n)。
小易爱回文
Description
网易2021校招笔试-音频算法工程师(提前批) 小易得到了一个仅包含大小写英文字符的字符串,该字符串可能不是回文串。 (“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串,“asds”就不是回文串。) 小易可以在字符串尾部加入任意数量的任意字符,使其字符串变成回文串。 现在请你编写一个程序,程序要能计算出小易可以得到的最短回文串。
输入格式
一行包括一个字符串S。S的长度小于1000。输出格式
一行包括一个字符串,代表答案。输入样例
noo输出样例
noon提示
注意回文串的长度可以是奇数,也可以是偶数。 拓展思考:如果长度达到100000,这个题目又该怎么处理呢?
蛇形方阵
Description
给出一个不大于 9 的正整数 n,输出 n×n 的蛇形方阵。 从左上角填上 1 开始,顺时针方向依次填入数字。 如同样例所示。注意每个数字有都会占用 3 个字符,前面使用空格补齐。
输入格式
一个整数n。输出格式
n对应的蛇形方阵。输入样例
4输出样例
1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7提示
注意输出格式!
拓展习题4
计算二叉树的第k层中所有叶子结点的个数
Description
二叉链表表示的二叉树:按先序次序输入二叉树中结点的值,'#'字符表示空树,构造二叉链表表示的二叉树T(该二叉树中的结点为单个字符并且无值重复的结点), 编写算法完成:计算二叉树的第k层中所有叶子结点个数,根结点为第1层,根结点的孩子结点为第2层,依次类推。 #include "stdio.h" #include "malloc.h" #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 typedef int Status; typedef char ElemType; typedef struct BiTNode{ ElemType data; struct BiTNode *lchild,*rchild;//左右孩子指针 } BiTNode,*BiTree; Status CreateBiTree(BiTree &T) { // 算法6.4 // 按先序次序输入二叉树中结点的值(一个字符),’#’字符表示空树, // 构造二叉链表表示的二叉树T。 char ch; scanf("%c",&ch); if (ch=='#') T = NULL; else { if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))) return ERROR; ________________________ // 生成根结点 _______________________ // 构造左子树 _________________________ // 构造右子树 } return OK; } // CreateBiTree int main() //主函数 { //补充代码 }//main
输入格式
第一行输入先序次序二叉树中结点 第二行输入层次k输出格式
第一行输出该二叉树的第k层中所有叶子结点个数输入样例
ABC###D## 2输出样例
1
二叉树的之字形遍历
Description
题目来源:字节跳动测试题 给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替) 例如: 给定的二叉树是{3,9,20,15,7,#,#}, 该二叉树之字形层序遍历的结果是 3 20 9 15 7正在上传…重新上传取消
输入格式
一行字符串,只包含大写字母和#。 此处采用完全二叉树的顺序存储结构。输出格式
若干行,之字形输出树的结点,每一行输出树的一层。输入样例
ABC###D##输出样例
A C B D
二叉树的右视图
Description
字节跳动2021面试题 给定一个二叉树的根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 比如此树 1 <--- / \ 2 3 <--- \ 5 <--- 从右侧看过去,答案是1,3,5。 实际上右视图就是二叉树层次遍历时每一层最右侧节点序列。
#include <stdio.h>
#include <malloc.h>
typedef long long ll;
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;
void CreateBiTree(BiTree &T)
{ /**< 先序建树算法 */
char ch;
scanf("%c",&ch);
if (ch=='#') T = NULL;
else
{
T = (BiTNode *)malloc(sizeof(BiTNode));
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
void Rview(BiTree T)
{/**< 右视图算法,用队列作为辅助存储结构 */
_______________________
}
int main()
{
BiTree T;
CreateBiTree(T);
Rview(T);
return 0;
}
输入格式
输入二叉树的先序序列(只包含大写字母和#,大写字母代表树节点)。输出格式
输出右视图的结果序列。输入样例
AB##C##输出样例
AC提示
层次遍历使用队列作为辅助结构,处理每一层的时队列的队尾元素就是每一层的最后一个节点。
树上摘樱桃
Description
网易2021校招笔试-算法工程师(正式第一批) 有一棵二叉树,树上的叶子节点定义为“樱桃”。现在需要找出树上有多少个满足如下子结构的“樱桃”串,即一串上刚好有两颗“樱桃”。 简单说,就是某个节点的左右孩子都是叶子节点,即为一个串。 比如如下的一棵树,红框标示的有两个符合要求的结构,答案就是2正在上传…重新上传取消
输入格式
第一行两个正整数m, n,空格分开,分别代表总共有树上有多少个节点,和树上有多少条边,2<=m<=100, 1<=n<=100 下面有n行,每行为3个部分,用空格分割,第一个数字为某非叶子节点的id, 第二个为该边为left还是right,第三个为子节点的id 注意:节点id彼此不会重复,id 1为根节点输出格式
一个整数,标示符合要求的结构的数量。输入样例
10 9 1 left 2 1 right 3 2 left 4 2 right 5 3 right 6 6 left 7 6 right 8 8 left 9 8 right 10输出样例
2提示
如题目说明的第一个样例图,可以看到,2-4-5子串,8-9-10子串,两个子串符合条件,所以答案为2
二叉树的最长路径
Description
二叉树中,任意两个节点间都存在一条唯一的路径,请求出所有路径中最长的路径长度。
输入格式
第一行为一个整数n,表示结点个数,结点以数字编号,根节点为1。n<10 第二行为一个数字和#号组成的字符串,采用完全二叉树的存储形式,#表示空树。输出格式
输出所有路径中最长的路径长度输入样例
5 1234##5输出样例
4提示
样例最长路径为(4,5),路径长度为4
测验习题
不同的字符
描述
不同的字符 统计一个全部由小写字母组成的字符串中有多少种字符。 例如baddff有4种字符,分别是a,b,c,d输入格式
仅一行,一个长度小于10000的字符串输出格式
输出不同字符的个数。输入样例
fabbddd输出样例
4
组队
描述
组队 老师把学生们分为A和B两个小组,人数分别是n和m,每个成员都有一个具体的能力值。 现在打算派出一些队伍参加比赛,每个队伍必须由一名A组成员和一名B组成员组成, 且两个成员的能力值之和必须恰好为d。 请你计算下,最多可以派出多少支参赛队伍。输入格式
第一行是三个整数n(1<=n<=1000)、m(1<=m<=1000)和d(1<=d<=100000000),分别表示A组人数,B组人数和要求的d。 第二行是n个整数ai(1<=ai<=100000000),表示A组成员的能力值。 第三行是m个整数bi(1<=bi<=100000000),表示B组成员的能力值。输出格式
输出一个整数,表示最多可以派出多少支参赛队伍,答案可能为0。输入样例
5 4 10 1 2 3 4 5 6 6 5 8输出样例
3
小球(树结构)
描述
一颗满二叉树的每一个结点都有一个整数权值,现在一个小球从树根上下落, 下落过程中它可以选择左右两个分支的任意一个,并获取结点的权值。 请问当小球掉落到最后一层时,它能获取的最大值。如下图,二叉树序列11 4 2 5 1 9 3 的最大值为22,小球依次获取11,2,9。正在上传…重新上传取消
输入格式
第一行一个整数n,代表满二叉树结点数量。n<=100 第二行n个整数,代表二叉树各结点权值。输出格式
小球掉落到最后一层时,它能获取的最大值。输入样例
7 11 4 2 5 1 9 3输出样例
22
最小的特殊数字
描述
用全部N(N<=10)个0-9的数字组成一个“有效”整数(即没有前置0的整数), 求这些组成的数中能被K(0<K<10^10)整除的最小数字。输入格式
输入分两行,第一行输入N, K,第二行输入N个数字。输出格式
输出满足条件的最小的数(不含前置0),如果没有满足条件的数输出 -1。输入样例
4 7 4 0 1 3输出样例
1043提示
413 % 7 = 0, 但是有前置0,所以满足条件的最小数是 1043 % 7 = 0。 此类题目需注意特殊情况,比如n=1时,如只输入一个0,答案只能是0。 注意long long