实验室二面题解
找第一个只出现一次的字符
题目描述
给定一个只包含小写字母的字符串,请你找到第一个仅出现一次的字符。如果没有,输出 no。
输入格式
一个字符串,长度小于 1100。
输出格式
输出第一个仅出现一次的字符,若没有则输出 no。
输入输出样例 #1
输入 #1
abcabd
输出 #1
c
输入输出样例 #2
输入 #2
aabbcc
输出 #2
no
考查知识点
字符串
解题思路
- 将字符串存入
str中,定义数组count用于统计每个字符出现的次数 - 循环一遍
str将字符映射到count索引中 - 再循环一遍
str查找第一次出现的字符,找到后输出并break结束循环,其中定义found用于标记是否找到
代码实现
#include<stdio.h>
#include<string.h>
int main(){
char str[1100];
scanf("%s", &str);
int len = strlen(str);
int count[26] = {0};
for (int i = 0; i < len; i++) {
count[str[i] - 'a']++;
}
int found = 0;
for (int i = 0; i < len; i++) {
if (count[str[i] - 'a'] == 1) {
printf("%c", str[i]);
found = 1;
break;
}
}
if (found == 0) {
printf("no");
}
return 0;
}
素数回文数的个数
题目描述
求 11到 n 之间(包括 n),既是素数又是回文数的整数有多少个。
输入格式
一个大于 11 小于 10000 的整数 n。
输出格式
11 到 n 之间的素数回文数个数。
输入输出样例 #1
输入 #1
23
输出 #1
1
说明/提示
回文数指左右对称的数,如:11,12121。
考查知识点
素数,回文数的判断
解题思路
- 定义两个函数
isPrime,isPalindrome分别判断是否符合素数和回文数 isPrime:一个数小于等于 1 直接返回 0 ,一定不为素数。若大于等于 2 ,检查是否存在有除了自己和 1 以外的余数,有则返回 0 ,说明不是素数。其中因数只用检查到其平方根isPalindrome:定义反转后的数reversed并初始化为 0 ,定义num替换原数x,通过while循环计算反转后的数,即反转后的数每次循环乘以 10 加上原数取余(最低位)的数,相当于原数的最低位作为反转后的数的最高位。最后检查反转后的数是否等于原数来判断是否为回文数
代码实现
#include<stdio.h>
#include<math.h>
int isPrime(int x) {
if (x <= 1) {
return 0;
}
for (int i = 2; i <= sqrt(x); i++) {
if (x % i == 0) {
return 0;
}
}
return 1;
}
int isPalindrome(int x) {
int reversed = 0;
int num = x;
while (x != 0) {
reversed = reversed * 10 + x % 10;
x /= 10;
}
return num == reversed;
}
int main() {
int n;
scanf("%d", &n);
int count = 0;
for (int i = 11; i <= n; i++) {
if (isPrime(i) && isPalindrome(i)) {
count++;
}
}
printf("%d", count);
return 0;
}
基因相关性
题目描述
为了获知基因序列在功能和结构上的相似性,经常需要将几条不同序列的 DNA 进行比对,以判断该比对的 DNA 是否具有相关性。
现比对两条长度相同的 DNA 序列。首先定义两条 DNA 序列相同位置的碱基为一个碱基对,如果一个碱基对中的两个碱基相同的话,则称为相同碱基对。接着计算相同碱基对占总碱基对数量的比例,如果该比例大于等于给定阈值时则判定该两条 DNA 序列是相关的,否则不相关。
输入格式
有三行,第一行是用来判定出两条 DNA 序列是否相关的阈值,随后 2行是两条 DNA 序列(长度不大于 500)。
输出格式
若两条 DNA 序列相关,则输出 yes,否则输出no。
输入输出样例 #1
输入 #1
0.85
ATCGCCGTAAGTAACGGTTTTAAATAGGCC
ATCGCCGGAAGTAACGGTCTTAAATAGGCC
输出 #1
yes
考查知识点
数组存储字符串
解题思路
- 将两个DNA序列存入两个数组
DNA1,DNA2中 - 遍历一个数组逐个比对每个字符是否相同
- 计算相同字符数个数
same和所占比例rate,对比阈值threshold和相同字符所占比例rate。若大于阈值,则输出yes,否则输出no
代码实现
#include<stdio.h>
#include<string.h>
int main() {
double threshold;
scanf("%lf", &threshold);
char DNA1[501], DNA2[501];
scanf("%s", &DNA1);
scanf("%s", &DNA2);
int len = strlen(DNA1);
int same = 0;
for (int i = 0; i < len; i++) {
if (DNA1[i] == DNA2[i]) {
same++;
}
}
double rate = (double)same / len;
if (rate >= threshold) {
printf("yes");
} else {
printf("no");
}
return 0;
}
欢乐的跳
题目描述
一个 n 个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了 [1,n-1] 之间的所有整数,则称之符合“欢乐的跳”,如数组 {1,4,2,3} 符合“欢乐的跳”,因为差的绝对值分别为:3,2,1。
给定一个数组,你的任务是判断该数组是否符合“欢乐的跳”。
输入格式
每组测试数据第一行以一个整数 n(1 <= n <= 1000) 开始,接下来 n 个空格隔开的在 [-108,108] 之间的整数。
输出格式
对于每组测试数据,输出一行若该数组符合“欢乐的跳”则输出 Jolly,否则输出 Not jolly。
输入输出样例 #1
输入 #1
4 1 4 2 3
输出 #1
Jolly
输入输出样例 #2
输入 #2
5 1 4 2 -1 6
输出 #2
Not jolly
说明/提示
1 <= n <= 1000
考查知识点
数组
解题思路
- 读取数组
number,初始化差的绝对值数组diffs,定义found并初始化为 1 标记差值是否出现 - 遍历数组,计算两个连续元素之间差的绝对值
diff - 检查差的绝对值是否在要求范围内且出现一次
- 根据
found标记输出。若为 1 ,则输出Jolly,否则输出Not jolly
代码实现
#include<stdio.h>
#include<stdlib.h>
int main() {
int n;
scanf("%d", &n);
int number[n];
for (int i = 0; i < n; i++) {
scanf("%d", &number[i]);
}
int diffs[n];
for (int i = 0; i < n; i++) {
diffs[i] = 0;
}
int found = 1;
for (int i = 1; i < n; i++) {
int diff = abs(number[i] - number[i - 1]);
if (diff >= 1 && diff <= n - 1) {
if (diffs[diff - 1] == 0) {
diffs[diff - 1] = 1;
} else {
found = 0;
break;
}
} else {
found = 0;
break;
}
}
if (found == 1) {
printf("Jolly");
} else {
printf("Not jolly");
}
return 0;
}
开关灯
题目描述
假设有 N 盏灯(N 为不大于 5000 的正整数),从 1 到 N 按顺序依次编号,初始时全部处于开启状态;第一个人(1 号)将灯全部关闭,第二个人(2 号)将编号为 2 的倍数的灯打开,第三个人(3 号)将编号为 3 的倍数的灯做相反处理(即,将打开的灯关闭,将关闭的灯打开)。依照编号递增顺序,以后的人都和 3 号一样,将凡是自己编号倍数的灯做相反处理。问当第 N 个人操作完之后,有哪些灯是关闭着的?
输入格式
输入为一行,一个整数 N,为灯的数量。
输出格式
输出为一行,按顺序输出关着的灯的编号。编号与编号之间间隔一个空格。
输入输出样例 #1
输入 #1
10
输出 #1
1 4 9
输入输出样例 #2
输入 #2
5
输出 #2
1 4
考查知识点
寻找因数
解题思路
- 初始化
count来存储因数个数 - 因为偶数个人操作后,灯的状态不变(开),奇数个人操作后,状态相反。又因为只有完全平方数的因数为奇数,因此最终关闭的灯为完全平方数的灯
代码实现
#include<stdio.h>
#include<math.h>
int main() {
int n;
scanf ("%d", &n);
for (int i = 1; i <= sqrt(n); i++) {
printf ("%d ", i * i);
}
return 0;
}
二进制分类
题目描述
若将一个正整数化为二进制数,在此二进制数中,我们将数字 1 的个数多于数字 0 的个数的这类二进制数称为 A 类数,否则就称其为 B 类数。
例如:
(13)_{10}=(1101)_2,其中 1 的个数为 3,0 的个数为 1,则称此数为 A 类数;
(10)_{10}=(1010)_2,其中 1 的个数为 2,0 的个数也为 2,称此数为 B 类数;
(24)_{10}=(11000)_2,其中 1 的个数为 2,0 的个数为 3,则称此数为 B 类数;
程序要求:求出 1~n 之中(1 <= n <= 1000),全部 A,B 两类数的个数。
输入格式
输入 n。
输出格式
一行,包含两个整数,分别是 A 类数和 B 类数的个数,中间用单个空格隔开。
输入输出样例 #1
输入 #1
7
输出 #1
5 2
考查知识点
十进制转二进制
解题思路
ten_two函数:初始化转化为二进制后的数result为 0 ,使用while循环,通过 t 每次乘 10 将原十进制数除以二后的余数从个位起存入,最终得到转化后的二进制数AB:初始化二进制数中 0 和 1 的个数为 0 ,使用while循环,将二进制数的最后一位读取,计算二进制数中 0 和 1 的个数,如果 1 的个数大于 0 的个数,返回 1 ,否则,返回 0- 计算A类数,B类数个数并输出
代码实现
#include<stdio.h>
int ten_two(int x) {
int result = 0;
int t = 1;
while (x) {
result += (t * (x % 2));
x /= 2;
t *= 10;
}
return result;
}
int AB(int result) {
int countone = 0;
int countzero = 0;
while (result) {
if (result % 10 == 0) {
countzero++;
} else {
countone++;
}
result /= 10;
}
if (countone > countzero) {
return 1;
} else {
return 0;
}
}
int main() {
int n;
scanf("%d", &n);
int A = 0;
int B = 0;
for (int i = 1; i <= n; i++) {
int num = ten_two(i);
if (AB(num) == 1) {
A++;
} else {
B++;
}
}
printf("%d %d", A, B);
return 0;
}
点亮灯笼
题目描述
有 n 个灯笼环形摆放。最开始,这些灯笼都是关闭的状态。
操作台上有 n 个按钮,按下第 x 个按钮时,会反转灯笼 x 以及相邻两个灯笼的状态。「反转」是指关闭变成点亮、点亮变成关闭。
举一个例子:如果按下第 5 个按钮,则 4、5、6 号灯笼都会反转;如果按下第 n 个按钮,则 n-1, n, 1 这三个灯笼状态反转。这是因为灯笼放置为环形,n-1 和 1 是与 n 相邻的灯笼。
我们依次按下了一些按钮。你需要编程求出当我们的操作完成后,最终这些灯笼的状态。
输入格式
第一行,两个正整数 n, m,分别表示共有 n 个灯笼、我们按了 m 次按钮。
接下来 m 行,每行一个正整数,表示我们在那一次操作中按下了哪个按钮。
输出格式
仅一行,n 个整数,依次表示 n 个灯笼的状态,用空格隔开。以 0 代表灯笼关闭,以 1 代表灯笼点亮。
输入输出样例 #1
输入 #1
5 4
1
3
1
2
输出 #1
1 0 0 1 0
说明/提示
样例解释
灯笼序列的状态如下:
0 0 0 0 0 # 初始状态
1 1 0 0 1 # 按下 1 之后的状态
1 0 1 1 1 # 按下 3 之后的状态
0 1 1 1 0 # 按下 1 之后的状态
1 0 0 1 0 # 按下 2 之后的状态
因此你应当输出 1 0 0 1 0。
数据规模与约定
对于 100% 的数据,有 n <= 1000,m <= 1000。
考查知识点
数组
解题思路
- 定义数组
lantern存储灯笼开闭状态并初始化所有灯笼为关闭状态,即数组为0。则 1 为开,0 为闭 - 定义
button为按钮编号作为索引。数组从 0 开始,所以button作为索引时需先减 1 - 反转指定灯笼及相邻两个灯笼状态。反转前一个时,需
button - 1 + n取余n以确保前一个仍为所有灯笼之一。反转后一个时,需button + 1取余n。因为该灯笼放置为环形 - 输出最终状态
代码实现
#include<stdio.h>
int main() {
int n, m;
scanf("%d %d", &n, &m);
int lantern[n];
for (int i = 0; i < n; i++) {
lantern[i] = 0;
}
for (int i = 0; i < m; i++) {
int button;
scanf("%d", &button);
button--;
lantern[button] = 1 - lantern[button];
lantern[(button + 1) % n] = 1 - lantern[(button + 1) % n];
lantern[(button - 1 + n) % n] = 1 - lantern[(button - 1 + n) % n];
}
for (int i = 0; i < n; i++) {
printf("%d ", lantern[i]);
}
return 0;
}
查找
题目描述
输入 n 个不超过 10^9 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a_1,a_2,…,a_{n},然后进行 m 次询问。对于每次询问,给出一个整数 q,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 -1 。
输入格式
第一行 2 个整数 n 和 m,表示数字个数和询问次数。
第二行 n 个整数,表示这些待查询的数字。
第三行 m 个整数,表示询问这些数字的编号,从 1 开始编号。
输出格式
输出一行,m 个整数,以空格隔开,表示答案。
输入输出样例 #1
输入 #1
11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6
输出 #1
1 2 -1
说明/提示
数据保证,1 <= n <= 10^6=,0 <= a_i,q <= 10^9,1 <= m <= 10^5
本题输入输出量较大,请使用较快的 IO 方式。
考查知识点
二分查找
解题思路
- 定义数组
arr为待查找的数组,num为需要查找的数的数组 - 二分查找:对于一个有序数列,先定义左边界为 0 ,右边界为
n-1,然后使用while循环来确保不越界,定义mid为中间数下标。用if语句判断,若所找数小于等于中间值,说明所找值在中间值左侧,因此更新r值为mid,相反同理更新l值为mid + 1。循环直至找到待查询的数字,输出下标为l + 1,若未找到,则输出-1
代码实现
#include<stdio.h>
int main() {
int n, m;
scanf("%d%d", &n, &m);
int arr[n], num[m];
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
for (int i = 0; i < m; i++) {
scanf("%d", &num[i]);
}
for (int i = 0; i < m; i++) {
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r) / 2;
if (num[i] <= arr[mid]) {
r = mid;
} else {
l = mid + 1;
}
}
if (arr[l] == num[i]) {
printf("%d ", l + 1);
} else {
printf("-1 ");
}
}
return 0;
}
排队接水
题目描述
有 n 个人在一个水龙头前排队接水,假如每个人接水的时间为 T_i,请编程找出这 n 个人排队的一种顺序,使得 n 个人的平均等待时间最小。
输入格式
第一行为一个整数 n。
第二行 n 个整数,第 i 个整数 T_i 表示第 i 个人的接水时间 T_i。
输出格式
输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。
输入输出样例 #1
输入 #1
10
56 12 1 99 1000 234 33 55 99 812
输出 #1
3 2 7 8 1 4 9 6 10 5
291.90
说明/提示
1<= n <= 1000,1<= t_i <= 10^6,不保证 t_i 不重复。
考查知识点
排序
解题思路
- 定义数组
watert,wait,index分别为每个人的接水时间,每个人的等待时间,重新排序后的下标 - 冒泡排序使新序列为等待时间最短的序列并调换下标
- 冒泡排序:遍历数组,从数组第一个元素开始,依次比较每对相邻的元素。若前一个元素大于后一个元素,则交换他们的位置和下标,重复以上直到排序完成
- 计算每个人的等待时间,即前一个人的等待时间和前一个人的接水时间的总和
- 计算总等待时间及其平均值,输出新序列下标
代码实现
#include<stdio.h>
int main() {
int n;
int watert[1001], wait[1001], index[1001];
long long watersum = 0, waitsum = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &watert[i]);
index[i] = i;
}
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (watert[j] > watert[j + 1]) {
int temp = watert[j];
watert[j] = watert[j + 1];
watert[j + 1] = temp;
temp = index[j];
index[j] = index[j + 1];
index[j + 1] = temp;
}
}
}
wait[0] = 0;
for (int i = 1; i < n; i++) {
wait[i] = wait[i - 1] + watert[i - 1];
waitsum += wait[i];
}
double average = (double) waitsum / n;
for (int i = 0; i < n; i++) {
printf("%d ", index[i] + 1);
}
printf("\n%.2lf", average);
return 0;
}

2046

被折叠的 条评论
为什么被折叠?



