蓝桥杯高校新生编程赛第三场题解——Java
01.对角线上的最值【新生编程赛】

完整解题代码:
import java.util.Scanner;
import java.util.Collections;
import java.util.ArrayList;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);//在此输入您的代码...int N=scan.nextInt();int[][] arr=new int[N][N];for(int i=0;i<n;i++){for(int j=0;j<n;j++){arr[i][j]=scan.nextInt();}}ArrayList<Integer> e=new ArrayList<>();for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(i==j || i+j==n-1){e.add(arr[i][j]);}}}int max=Collections.max(e);int min=Collections.min(e);System.out.println(max+" "+min);scan.close();}}
解题思路:
1.明确目标:本题需要我们找出 N×N 矩阵的主对角线和副对角线上所有元素的最大值和最小值,那么第一反应就是二维数组存数据,然后用各种各样的方法找最值。
2.读取输入:使用二维数组先读取矩阵的大小 N,再读取 N 行的矩阵元素。
3.收集元素:将输入数据转换为二维数组后,很容易想到用循环嵌套,遍历出主副对角线上的有限个元素。(元素位于主对角线时(行号i等于列号j)| | 副对角线(行号i + 列号j = N-1))
4.判断大小:因为是有限个元素,所以我们又考虑到利用动态数组ArrayList存储对角线上的元素,便于后续再次使用Collections.max()和Collections.min()方法进行最值计算。(详见“新生杯第一场03.设计师调度”)
5.输出结果:注意案例的输出最值之间有空格,因此我们使用增加空格“System.out.println(max+" "+min);”的输入方式。
涉及知识点:
1.二维数组:
创建和初始化二维数组
type[][] arrayName;//或type arrayName[][];其中初始化可分为静态初始化和动态初始化,本体因为要读取题目动态的输入,我们使用动态初始化。
静态初始化:
// 规则二维数组(每行长度相同)
int[][] matrix1 = {{1, 2, 3},{4, 5, 6},{7, 8, 9}
};// 不规则二维数组(每行长度不同)
int[][] matrix2 = {{1, 2}, // 第0行长度为2{3}, // 第1行长度为1{4, 5, 6} // 第2行长度为3
};动态初始化:
int n = 3;
int[][] matrix = new int[n][]; // 先初始化外层数组(3行)
// 再分别初始化每行(列数可不同)
matrix[0] = new int[3]; // 第0行3列
matrix[1] = new int[2]; // 第1行2列
matrix[2] = new int[4]; // 第2行4列// 简化写法(仅适用于规则数组,强制每行长度相同)
int[][] regularMatrix = new int[3][3]; // 3行3列的规则数组访问与遍历
通过 “行索引” 和 “列索引” 访问元素(索引从 0 开始),遍历需使用双重循环。
(1)元素访问
int[][] matrix = {{1,2}, {3,4,5}};
int element = matrix[1][2]; // 访问第1行第2列的元素(值为5)
matrix[0][1] = 10; // 修改第0行第1列的元素(改为10)
(2)遍历方式
- 普通 for 循环:适合需要索引的场景。
for (int i = 0; i < matrix.length; i++) { // 遍历行(matrix.length为行数)for (int j = 0; j < matrix[i].length; j++) { // 遍历当前行的列(matrix[i].length为当前行的列数)System.out.print(matrix[i][j] + " ");}System.out.println(); } - 增强 for 循环:适合仅需元素值、无需索引的场景。
for (int[] row : matrix) { // 遍历每行(row是当前行的一维数组)for (int num : row) { // 遍历当前行的每个元素System.out.print(num + " ");}System.out.println(); }
(3)特点与适用场景
- 长度固定:一旦初始化,行数和每行的列数不可变(不能动态添加 / 删除行或列)。
- 内存高效:元素在内存中连续存储(内层数组是连续的),随机访问速度快(通过索引直接定位)。
- 适用场景:存储结构固定的二维数据(如矩阵运算、表格数据),例如该题代码中用
int[][] arr存储 N×N 矩阵。
2.动态数组(ArrayList):
核心概念:
定义:
ArrayList是泛型类,需指定存储的元素类型(如ArrayList<Integer>存储整数),语法为ArrayList<数据类型> 集合名 = new ArrayList<>()。底层实现:内部维护一个
Object[]类型的数组(elementData),当元素数量超过当前容量时,自动创建新数组并复制旧元素(扩容)。
初始化:
// 无参构造:初始容量为0(JDK1.8后),添加第一个元素时扩容为10
ArrayList<Integer> list1 = new ArrayList<>();// 指定初始容量:减少扩容次数,适合已知大致元素数量的场景
ArrayList<String> list2 = new ArrayList<>(20); // 初始容量为20// 用其他集合初始化
ArrayList<Integer> list3 = new ArrayList<>(Arrays.asList(1, 2, 3));常用方法:
| 方法 | 功能描述 | 示例 |
|---|---|---|
add(E e) | 在末尾添加元素 | list.add(5); |
add(int index, E e) | 在指定索引插入元素 | list.add(1, 10); // 在索引 1 处插入 10 |
get(int index) | 获取指定索引的元素 | int num = list.get(2); |
set(int index, E e) | 修改指定索引的元素 | list.set(0, 20); // 修改索引 0 为 20 |
remove(int index) | 删除指定索引的元素,并返回被删除元素 | int removed = list.remove(1); |
size() | 返回元素个数 | int size = list.size(); |
isEmpty() | 判断是否为空 | boolean empty = list.isEmpty(); |
clear() | 清空所有元素 | list.clear(); |
3.二维数组与ArrayList的核心区别:
| 维度 | 二维数组(int[][]) | ArrayList |
|---|---|---|
| 数据结构 | 数组的数组(支持二维索引) | 动态扩容的一维数组(仅支持一维索引) |
| 长度特性 | 长度固定(行数和列数不可变) | 长度动态可变(自动扩容) |
| 元素类型 | 可存储基本类型(如int)或引用类型 | 仅能存储引用类型(需用包装类,如Integer) |
| 内存效率 | 更高(无额外扩容开销) | 较低(可能存在未使用的容量,扩容需复制) |
| 适用场景 | 固定结构的二维数据(如矩阵) | 元素数量不确定的一维数据(如动态列表) |
4.ArrayList中的最值操作(见过往博客如下):

5.for-each循环(增强for循环):
(因为啵猪第一次遇到该循环,遂单独列出学习一番。。。。。。。。)
增强for循环(也称为for-each循环)是Java从JDK 5开始引入的一种便捷循环语法,旨在简化对数组或集合类的迭代操作。
初始化for-each循环:
for(ElementType element: arrayName)
{ //集合或数组的数据类型 变量名:集合名/数组名System.out.println(变量名);
};
即:
for(数据类型 变量名:要遍历的数组){输出语句(变量名);
}
遍历数组:
遍历整型数组
增强for循环最常见的用途之一是遍历数组。它简化了传统for循环的语法,不需要维护索引变量。
int[] numbers = {10, 20, 30, 40, 50};for (int number : numbers) {System.out.println(number);
}输出:
10
20
30
40
50
遍历字符串数组
String[] fruits = {"Apple", "Banana", "Cherry"};for (String fruit : fruits) {System.out.println(fruit);
}输出:
Apple
Banana
Cherry
遍历二维数组
- 增强 for 循环可以嵌套使用,方便遍历多维数组。
- 二维数组本质上还是一个数组,只不过它的每个元素都是一个一维的数组。因此对二维数组进行遍历时,要嵌套遍历两次。
int[][] matrix = {{1, 2, 3},{4, 5, 6},{7, 8, 9}
};for (int[] row : matrix) {for (int element : row) {System.out.print(element + " ");}System.out.println();
}
输出:
1 2 3
4 5 6
7 8 9
注意事项:
无法修改集合结构:在增强for循环中,不能直接对集合进行add或remove操作,否则会抛出ConcurrentModificationException。
无法访问索引:增强for循环中无法直接获取元素的索引。如果需要索引,需使用传统for循环。
02.加工等级之和【新生编程赛】

完整解题代码1:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);int N = scan.nextInt(); // 读取组件数量int[] arr = new int[N]; // 存储加工等级数组// 读取所有加工等级for (int i = 0; i < N; i++) {arr[i] = scan.nextInt();}long sum = 0; // 存储结果总和(用long避免溢出)// 遍历每个加工等级,判断是否满足条件for (int num : arr) {// 情况1:等级为1时,num-1=0(不存在),直接加入总和if (num == 1) {sum += num;continue;}// 情况2:等级>1时,遍历原始数组检查是否存在num-1boolean ifLevel = false; // 标记是否存在num-1for (int n : arr) {if (n == num - 1) {ifLevel = true;break; // 找到后立即退出内层循环,减少无效操作}}// 如果不存在num-1,加入总和if (!ifLevel) {sum += num;}}System.out.println(sum);scan.close();}
}解题思路1:
1.明确目标:题目看起来有点绕,但实际上就是要我们统计每个加工等级的出现次数,但这个次数需要判断是否满足条件,最终累加符合条件的等级。
2.遍历判断:先遍历判断情况1:等级为1时,num-1=0(不存在),直接加入总和;
然后再次遍历判断关键的情况2:等级>1时,遍历原始数组检查是否存在num-1。
(等于说是多次遍历所有的加工等级,有超时风险,但在我看来是最直接的思路了)
3.统计输出:将最后的sum统计输出。
提交检测:

完整解题代码2:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);//在此输入您的代码...int N=scan.nextInt();int[] arr=new int[N];for(int i=0;i<N;i++){arr[i]=scan.nextInt(); }int[] count=new int[200000];for(int i=0;i<arr.length;i++){int num=arr[i];count[num]++;}long sum=0;for(int i=0;i<arr.length;i++){int num=arr[i];if(num==1 || count[num-1]==0){sum+=num;}}System.out.println(sum);scan.close();}
}解题思路2:
1.明确目标:题目看起来有点绕,但实际上就是要我们统计每个加工等级的出现次数,但这个次数需要判断是否满足条件,最终累加符合条件的等级。
(核心注意点:因为N和Aᵢ范围很大,有超时的风险,因此我们要选择引入数组count(提高效率的做法),而不是直接让代码每次都重新遍历整个原始数组去检查。)
2.引入计数数组统计:即第一遍循环遍历先统计所有的等级。我们先用数组读取两行输入,并用一个数组count记录每个加工等级在原始数组中出现的次数。
count的下标代表 “加工等级”(比如count[5]对应等级 5)。count的元素值代表 “该等级出现的次数”(比如count[5] = 3表示等级 5 出现了 3 次)。
举例说明:
假设原始数组
arr = [2, 3, 1, 3, 5](即 5 个组件的等级分别为 2、3、1、3、5)。遍历
arr时,每遇到一个等级num,就给count[num]加 1:
- 遇到
2→count[2] = 1- 遇到
3→count[3] = 1- 遇到
1→count[1] = 1- 再遇到
3→count[3] = 2(第二次出现)- 遇到
5→count[5] = 1最终
count数组中关键位置的值为:count[1] = 1,count[2] = 1,count[3] = 2,count[5] = 1(其他位置默认 0)。
3.增加求和逻辑:遍历原始数组中的每个等级num,判断其是否满足 “不存在等级为num-1的组件”,如果满足则加入总和sum。
分类讨论:
判断 “不存在等级为
num-1” 的两种情况:
当
num = 1时:num-1 = 0,而题目中加工等级是正整数(至少为 1),因此等级 0 必然不存在。所以num=1一定满足条件,必须加入总和。当
num > 1时:需检查count[num-1]的值:
- 如果
count[num-1] == 0:表示等级num-1在原始数组中从未出现过(即不存在),因此num满足条件,加入总和。- 如果
count[num-1] > 0:表示等级num-1存在,因此num不满足条件,不加入总和。进一步分析:
原始数组
arr = [2, 3, 1, 3, 5],count数组已统计完成。遍历每个
num:
- 第一个
num=2:num>1,检查count[2-1] = count[1] = 1(等级 1 存在)→ 不满足条件,不加入sum。- 第二个
num=3:num>1,检查count[3-1] = count[2] = 1(等级 2 存在)→ 不满足条件,不加入sum。- 第三个
num=1:(跳过检查,等级0不存在),满足num==1→ 加入sum,sum = 1。- 第四个
num=3:同第二个num=3,不满足条件,不加入sum。- 第五个
num=5:num>1,检查count[5-1] = count[4] = 0(等级 4 不存在)→ 满足条件,加入sum,sum = 1 + 5 = 6。最终
sum=6,即满足条件的等级之和为 6。
提交检测:

(时间上确实有所节省。。。。。)
03.蚀光之刃【新生编程赛】

完整解题代码:
public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);//在此输入您的代码...int A=scan.nextInt();int B=scan.nextInt();int C=scan.nextInt();int D=scan.nextInt();int num1;int num2;if(A==0){num1=Integer.MAX_VALUE;}else{num1=C/A;}if(B==0){num2=Integer.MAX_VALUE;}else{num2=D/B;}int max=Math.min(num1,num2);System.out.println(max);scan.close();}
}解题思路:
1.明确目标:(题目又是一如既往的花里胡哨。。。)实则就是要求分别计算出两个玩意各自能支持锻造的最大剑数;然后按要求与配方取两者的最小值,即为最终能锻造的最大剑数。就有点类似于木桶效应只能取到短板。
2.判断星银矿:分类讨论:
- 若
A = 0(锻造不需要星银矿),则星银矿无限制,将num1设为Integer.MAX_VALUE - 若
A > 0,则num1 = C / A(注意整数除法是自动向下取整,刚好能满足)。
3.判断龙之精粹:分类讨论同上:
- 若
B = 0(锻造不需要龙之精粹),则龙之精粹无限制,将num2设为Integer.MAX_VALUE; - 若
B > 0,则num2 = D / B(整数除法,向下取整)。
4.输出结果:利用Math函数输出num1,num2之间的最小值即可。
05.机器人的行动轨迹【新生编程赛】

完整解题代码:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);//在此输入您的代码...Long N=scan.nextLong();if(N<=3){System.out.println(N);}else{System.out.println(5*(N-3)+3);}scan.close();}
}解题思路:
。。。我就是列举出来找规律的,各位大佬对这题有更好的解法欢迎交流。。。
(ps:这该死的、丑陋的解答。。。)
04.代码纪元【新生编程赛】
(放到最后,这题没有做出来(反映出解决字符串问题较为薄弱的现状),遂借助AI学习)

样例输出:zaza
完整解题代码:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);String s = scan.next();// 步骤1:生成S的翻转串S'String revS = new StringBuilder(s).reverse().toString();// 步骤2:确定S和S'中的较大者maxSS(T只需大于maxSS,即可同时大于S和S')String maxSS = s.compareTo(revS) > 0 ? s : revS;// 步骤3:生成比maxSS大的最小字符串String t = getSmallestBiggerString(maxSS);System.out.println(t);scan.close();}public static String getSmallestBiggerString(String s) {char[] chars = s.toCharArray();int n = chars.length;int i = n-1;// 从右向左找第一个不是'z'的字符(用于“原长度内修改”)while (i >= 0 && chars[i] == 'z') {i--;}// 情况1:原长度内的“下一个字符串”String case1;if (i < 0) {// 全为'z',原长度内无法增大,只能在末尾加'a'case1 = s + "a";} else {// 找到的字符加1,右侧所有字符置为'a'(保证字典序最小)chars[i]++;for (int j = i + 1; j < n; j++) {chars[j] = 'a';}case1 = new String(chars);}// 情况2:原字符串末尾直接加'a'(长度+1)String case2 = s + "a";// 取两种情况中字典序较小的结果return case1.compareTo(case2) < 0 ? case1 : case2;}
}解题思路:
1.明确目标:本题要求找到字典序严格大于字符串 S 及其翻转串 S' 的最小字符串 T。
而题目给出的字典序的比较规则我们可以翻译为 :“逐位比较字符的 ASCII 码,若某一位字符不同,ASCII 小的字符串字典序更小;若所有位都相同,长度短的字典序更小”。(如题目样例,输入zaz,反转无影响,所以需要找到一个大于zaz的最小字符串,那就是+a,变成zaza。)
2.厘清步骤:
- 首先我得先生成翻转串
S',即将S反转得到其关联的标识串。 - 然后我得比较S、S'这两个字符串,取字典序较大的那个(记为
maxSS)。然后让T只需大于这个maxSS,就能同时满足 “大于S且大于S'”。 - 最后我就只需生成比
maxSS大的最小字符串,但我需考虑 “原长度内修改” 和 “长度加 1” 两种情况,最终取字典序更小的结果。
因此根据以上步骤的加粗部分,我想要分成六步操作:
(1)生成翻转串 S':想到利用 StringBuilder 的 reverse() 方法可以高效地将字符串反转。
(2)比较S、S'这两个字符串,取字典序较大:通过 String 的 compareTo 方法比较 S 和 S':若 S.compareTo(revS) > 0,说明 S 字典序更大,maxSS = S;否则 maxSS = revS。
(3)生成比 maxSS 大的最小字符串:
要找到字典序最小的更大字符串,需遵循 “尽可能在右侧修改,且修改后右侧字符尽可能小(置为 'a')” 的原则,分(4)、(5)两种情况处理:
(4)原长度内修改:
从右往左遍历,找到第一个不是 'z' 的字符:
- 若所有字符都是
'z'(如S = "zzz"),则原长度内无法增大,需在末尾加'a'(如"zzza")。 - 若找到非
'z'的字符(如S = "zaz",字符'a'位于索引 1),则将该字符加 1('a'→'b'),并将其右侧所有字符置为'a'(保证字典序最小),得到case1 = "zba"。
(5)长度加 1:
直接在 maxSS 末尾添加 'a'(如 S = "zaz" 时,case2 = "zaza")。
(6)取字典序更小:
比较 case1 和 case2 的字典序,取更小的那个作为结果。
(思路清晰了,下面学习并分析AI的方法和语句使用)
涉及知识点:
1.反转字符串 StringBuilder 的 reverse()方法
reverse()方法用于反转StringBuilder中字// 步骤1:生成S的翻转串S'String revS = new StringBuilder(s).reverse().toString();符的顺序。这是一个非常直接且高效的操作,尤其适用于需要对字符串进行倒序处理的场景。
代码示例:
public class StringBuilder {public static void main(String[] args) {StringBuilder sb = new StringBuilder("Hello World");sb.reverse();System.out.println(sb); }
}输出: dlroW olleH
题目中相关代码:
// 步骤1:生成S的翻转串S'String revS = new StringBuilder(s).reverse().toString();代码解读:
惊到了,这一行就完成了,遂继续追问AI,原来这种写法利用了方法链式调用的特性
并告诉我这种写法在逻辑和功能上与分开写是完全等价的,只是代码更简洁。
拆解如下:
new StringBuilder(s):创建一个包含字符串s的StringBuilder对象。.reverse():对StringBuilder中的字符串进行反转(该方法返回StringBuilder自身,因此可以继续调用其他方法)。.toString():将反转后的StringBuilder对象转换为String类型,最终赋值给revS。(这种链式调用是 Java 中常见的 “流式编程” 风格,能在保证可读性的前提下,让代码更简洁高效。)
2.比较字符串 String 的 compareTo ()方法
compareTo() 方法用于两种方式的比较:
- 字符串与对象进行比较。
- 按字典顺序比较两个字符串。
语法:
int compareTo(Object o)或int compareTo(String anotherString)参数:
o -- 要比较的对象。
anotherString -- 要比较的字符串。
返回值:
返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的长度差值,如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至比较的字符或被比较的字符有一方结束。
- 如果参数字符串等于此字符串,则返回值 0;
- 如果此字符串小于字符串参数,则返回一个小于 0 的值;
- 如果此字符串大于字符串参数,则返回一个大于 0 的值。
说明:
如果第一个字符和参数的第一个字符不等,结束比较,返回第一个字符的ASCII码差值。
如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至不等为止,返回该字符的ASCII码差值。 如果两个字符串不一样长,可对应字符又完全一样,则返回两个字符串的长度差值。
代码实例:
public class Test {public static void main(String args[]) {String str1 = "Strings";String str2 = "Strings";String str3 = "Strings123";int result = str1.compareTo( str2 );System.out.println(result);result = str2.compareTo( str3 );System.out.println(result);result = str3.compareTo( str1 );System.out.println(result);}
}以上程序执行结果为:
0
-3
-3
3.三目运算符 ? :—— 根据条件选值
同时注意到这段代码:
// 步骤2:确定S和S'中的较大者maxSS(T只需大于maxSS,即可同时大于S和S')String maxSS = s.compareTo(revS) > 0 ? s : revS;经求助,使用了三目运算符
同时,祛魅一下,这等同于
String maxSS;
if (s.compareTo(revS) > 0) {// 如果s的字典序严格大于revS,maxSS取smaxSS = s;
} else {// 否则,maxSS取revSmaxSS = revS;
}解析三目运算符
三目运算符的格式是:
条件 ? 表达式1 : 表达式2执行逻辑:先判断 “条件” 是否为true;
- 若为
true,整个表达式的结果为表达式 1; - 若为
false,整个表达式的结果为表达式 2。
在本题中,
String maxSS = s.compareTo(revS) > 0 ? s : revS;的每一部分含义如下:
条件部分:
s.compareTo(revS) > 0这里调用了String的compareTo方法,用于比较s和revS的字典序:
- 若返回值
>0,说明s的字典序严格大于revS;- 若返回值
≤0,说明revS的字典序大于或等于s。表达式 1:
s当 “条件为
true” 时,maxSS被赋值为s。3.表达式 2:
revS
当 “条件为false” 时,maxSS被赋值为revS。
适用场景
三目运算符适合 **“条件判断后仅需简单赋值”** 的场景,能让代码更紧凑。但如果逻辑复杂(比如条件后需要执行多行代码),则建议还是用
if-else,避免代码可读性下降。
4.代码封装
注意到该解题代码单独封装了生成 “比输入字符串大的最小字符串”的方法
main方法的职责是 “统筹全局”:读取输入、生成翻转串、确定基准串maxSS、调用工具方法生成结果、输出答案。getSmallestBiggerString的职责是 “专注细节”:只负责生成 “比输入字符串大的最小字符串” 这一具体功能。
好处
便于复用和修改
如果未来需要多次使用 “生成比某个字符串大的最小字符串” 这个功能(比如题目扩展为处理多个字符串),封装成方法后可以直接调用(getSmallestBiggerString(s1)、getSmallestBiggerString(s2)),避免重复写相同的代码。
// 步骤3:生成比maxSS大的最小字符串String t = getSmallestBiggerString(maxSS);System.out.println(t);(在主函数直接调用输出结果)
可行性
在 Java 中,方法的核心作用就是 “封装一段独立的逻辑”。它可以接收输入参数(比如
getSmallestBiggerString的参数String s),执行一系列操作后返回结果(比如返回生成的字符串case1或case2)。
