试题 B: 寻找 2020——答案:16520
本题总分:5 分
【问题描述】
小蓝有一个数字矩阵,里面只包含数字 0 和 2。小蓝很喜欢 2020,他想找到这个数字矩阵中有多少个 2020 。
小蓝只关注三种构成 2020 的方式:
• 同一行里面连续四个字符从左到右构成 2020。
• 同一列里面连续四个字符从上到下构成 2020。
• 在一条从左上到右下的斜线上连续四个字符,从左上到右下构成 2020。
例如,对于下面的矩阵:
220000
000000
002202
000000
000022
002020
一共有 5 个 2020。其中 1 个是在同一行里的,1 个是在同一列里的,3 个是斜线上的。
小蓝的矩阵比上面的矩阵要大,如下给出了小蓝的矩阵。
请帮助小蓝确定在他的矩阵中有多少个 2020。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【解析】:定义二维矩阵,遍历每个坐标,以每个坐标为起点分别向右向下向右下三个方向遍历。
打开记事本,鼠标放到最后一行最后一列,可以知道,是一个300行300列的矩阵。然后直接暴力三次循环,分别是从左到右,从上到下,从左上到右下方向。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int[][] num = new int[301][301];
for (int i = 1; i <= 300; i++) {
String str = sc.next();
for (int j = 1; j <= str.length(); j++) {
num[i][j] = str.charAt(j - 1) - '0';
}
}
int ans = 0;
for (int i = 1; i <= 300; i++) {
for (int j = 1; j <= 300; j++) {
if (i + 3 <= 300 && num[i][j] == 2 && num[i + 1][j] == 0 && num[i + 2][j] == 2 && num[i + 3][j] == 0)
ans++;
}
}
for (int i = 1; i <= 300; i++) {
for (int j = 1; j <= 300; j++) {
if (j + 3 <= 300 && num[i][j] == 2 && num[i][j + 1] == 0 && num[i][j + 2] == 2 && num[i][j + 3] == 0)
ans++;
}
}
for (int i = 1; i <= 300; i++) {
for (int j = 1; j <= 300; j++) {
if (i + 3 <= 300 && j + 3 <= 300 && num[i][j] == 2 && num[i + 1][j + 1] == 0 && num[i + 2][j + 2] == 2
&& num[i + 3][j + 3] == 0)
ans++;
}
}
System.out.println(ans);
}
}
四、试题 D: 七段码——答案:80
【问题描述】
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二 极管,分别标记为 a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符 的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【答案】:80
【解析】:并查集+DFS
学习:https://blog.csdn.net/m0_55858611/article/details/123959722
https://blog.csdn.net/weixin_41793113/article/details/88762953
public class 七段码 {
public static int[][]e=new int[8][8];;
public static boolean[] isTrue=new boolean[8];
public static int[]father=new int[8];
public static int ans=0;
public static void main(String[] args) {
// TODO Auto-generated method stub
//连边建图
//a b c d e f g
//1 2 3 4 5 6 7
//e[i][j]=1表示i灯光和j灯光是相互连接的
e[1][2]=e[1][6]=1;
e[2][1]=e[2][7]=e[2][3]=1;
e[3][2]=e[3][4]=e[3][7]=1;
e[4][3]=e[4][5]=1;
e[5][4]=e[5][6]=e[5][7]=1;
e[6][1]=e[6][5]=e[6][7]=1;
dfs(1);
System.out.print(ans);
}
public static void dfs(int k) {
if(k==8) {
for(int i=1;i<=7;i++) {//初始化每一个父节点
father[i]=i;
}
for(int i=1;i<=7;i++) {
for(int j=1;j<=7;j++) {
if(isTrue[i]&&isTrue[j]&&e[i][j]==1) {
father[find(i)]=find(j);
}
}
}
int cnt=0;
for(int i=1;i<=7;i++) {
if(isTrue[i]&&father[i]==i) {
cnt++;
}
}
//当有且仅有一种联通亮灯情况的时候才合法,这个时候ans++
if(cnt==1)ans++;
return;//这句必须加上
}
isTrue[k]=true;
dfs(k+1);
isTrue[k]=false;
dfs(k+1);
}
static int find(int x) {
if(father[x]==x)
return x;
return father[x] = find(father[x]);
}
}
试题 E: 排序——jonmlkihgfedcba
本题总分:15 分
【问题描述】
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。
小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串 lan 排序,只需要 1 次交换。对于字符串 qiao 排序,总共需要 4 次交换。
小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要 100 次交换,可是他忘了吧这个字符串记下来,现在找不到了。
请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对该串的字符排序,正好需要 100 次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中可以包含相同的字符。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个只包含小写英文字母的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。
【答案】:jonmlkihgfedcba
【解析】:冒泡排序,要求字符串最短,那就假设完全逆序,设长度为n,则移动次数为 n*(n-1)/2,要求移动次数恰好大于100,则 n=15;移动次数105。要求字典序最小,则把第六个字符移动到第一个位置,前五个字符后移一位。纯逻辑推导,无代码。
思路: 首先要注意最后得到的字符串全是英文小写字母并且不重复。接下来进行分析,最后要求结果在最短的前提下字典序最小。那么我们先想办法找到最短的结果。
最短,那是能多短就多短。最短是长度是1,但是肯定不可能,因为他还要求字符串进行了100次交换,那么长度为2可不可以呢?也不行,长度为2的字符串最多进行一次交换。
一个长度为n的字符串,如果进行冒泡排序,假设他每次比较都进行了交换,那么它最多交换 (n-1)+(n-2)+…+1 = n*(n-1)/2 (进行n-1趟操作,第一趟操作交换n-1次,之后每趟交换的次数依次递减)。
在n*(n-1)/2>=100的前提下,n的最小值是15。也就是说,最后结果的字符串的长度至少15(低于15,它根本连交换100次的要求都达不到)。接下来再和题目要求的字典序最小一起考虑。
首先了解一下字典序:字典序是指从前到后比较两个字符串的大小的方法。首先比较第一个字符,如果不同则第一个字符较小的字符串更小,如果相同则继续比较第2个字符…如此继续,来比较整个字符串的大小。
现在我们知道字符串全是英文小写字母,并且长度为15且各不相同,那么我们可以确定这15个字母就是前15个小写英文字母abcdefghijklklmno,怎么排现在还不知道。
用逆向思维思考,若这15个字母每次冒泡两两比较都进行交换,能交换 15*(15-1) = 105次,那这个字符串只可能是这15个字母的逆序:onmlkjighfedecba。
然后我们再想办法减少逆序字符串的5次比较,并且使最后得到的结果字典序最小,只需要把逆序字符串的第六位提前至第一位:jonmlkighfedecba。在这种情况下,字典序就是最小的,我只需要第一位比你小,我就是字典序最小的。而且第1,2,3,4,5趟,每次j会分别和o,n,m,k,l进行比较,但是不交换,这样就省下了5次交换,且最后一共交换105-5=100次。
试题 G: 单词分析
时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。
【输入格式】
输入一行包含一个单词,单词只由小写英文字母组成。
【输出格式】
输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪个。如果有多个字母出现的次数相等,输出字典序最小的那个。
第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。
【样例输入】
lanqiao
【样例输出】
a
2
【样例输入】
longlonglongistoolong
【样例输出】
o
6
【评测用例规模与约定】
对于所有的评测用例,输入的单词长度不超过 1000。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
char charArray[] = sc.next().toCharArray(); // 字符数组
int nums[] = new int[26]; // int型数组 记录 每个字母的出现次数
for (int i = 0; i < charArray.length; i++) {
nums[charArray[i] - 'a']++;
}
int ans = nums[0], index = 0;
for (int i = 0; i < 26; i++) {
if (nums[i] > ans) {
ans = nums[i];
index = i;
}
}
System.out.println((char) ('a' + index) + "\n" + ans);
}
}
试题 H: 数字三角形
时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。
【输入格式】
输入的第一行包含一个整数 N (1 < N ≤ 100),表示三角形的行数。下面的 N 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。
【输出格式】
输出一个整数,表示答案。
【样例输入】
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
【样例输出】
27
import java.util.Scanner;
public class ShuziSanjiao {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int arr[][] = new int[n + 1][n + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
arr[i][j] = sc.nextInt();
arr[i][j] += Math.max(arr[i - 1][j - 1], arr[i - 1][j]);
}
}
System.out.println(n % 2 == 1 ? arr[n][n / 2 + 1] : Math.max(arr[n][n / 2], arr[n][n / 2 + 1]));
}
}