Java面向对象程序程序设计PTA题目解析一
字符串操作
给定一个字符串。请去除串中的数字并反转。
输入格式: 原始串。
输出格式: 去除数字后的反转字符串。
输入样例: 在这里给出一组输入。例如: he11ll00o w0or8ld!
输出样例: 在这里给出相应的输出。例如: !dlrow olleh
import java.util.Scanner; // 导入java.util包中的Scanner类,用于读取用户输入
public class Main { // 定义一个公开的类Main,它是这个程序的入口点
public static void main(String[] args) { // 定义main方法,它是程序的入口点
Scanner s = new Scanner(System.in); // 创建一个Scanner对象s,用于读取来自标准输入流(通常是键盘)的数据
String str = s.nextLine(); // 调用s的nextLine方法读取一行文本,并将其存储在字符串变量str中
// 使用for循环从字符串的最后一个字符开始向前遍历
for (int i = str.length() - 1; i >= 0; i--) {
char c = str.charAt(i); // 在循环的每次迭代中,通过调用str的charAt方法并传入索引i来获取当前字符,然后将其存储在字符变量c中
// 使用Character类的isDigit静态方法来检查变量c中的字符是否为数字
if (!Character.isDigit(c)) {
// 如果c不是数字,则执行打印操作
System.out.print(c); // 调用System.out的print方法将字符c输出到控制台,这里不会换行
}
}
}
}
注意:这里使用的是System.out.print而不是System.out.println,这意味着输出将不会在每个字符后换行,而是连续输出直到所有非数字字符都被逆序打印出来。
str的charAt方法:在Java中,String 类的 charAt 方法用于获取字符串中指定索引位置上的字符。这个方法接受一个整数参数,即字符的索引(位置),并返回该位置上的 char 类型的值。索引值从0开始,即字符串的第一个字符的索引是0,第二个字符的索引是1,依此类推,直到字符串的最后一个字符。
如果索引值超出了字符串的范围(即小于0或大于等于字符串的长度),那么 charAt 方法会抛出一个 StringIndexOutOfBoundsException 异常。
public class Main {
public static void main(String[] args) {
String str = "Hello, World!";
// 获取索引为7的字符(注意:索引从0开始)
char ch = str.charAt(7);
// 输出结果将是 'W',因为 'W' 是字符串 "Hello, World!" 中索引为7的字符
System.out.println(ch);
}
}
在这个例子中,字符串 str 包含文本 “Hello, World!”。我们通过调用 str.charAt(7) 来获取索引为7的字符,即 ‘W’,并将其存储在字符变量 ch 中。然后,我们使用 System.out.println(ch); 来打印这个字符。
需要注意的是,如果尝试访问一个不存在的索引(比如 str.charAt(str.length()) 或 str.charAt(-1)),那么将会抛出 StringIndexOutOfBoundsException 异常。因此,在使用 charAt 方法时,确保提供的索引在有效范围内是很重要的。
Character类的isDigit静态方法:Character 类的 isDigit 静态方法用于判断指定的字符是否是一个数字。该方法接受一个 char 类型的参数,如果参数是一个数字(即介于 ‘0’ 到 ‘9’ 之间的字符),则返回 true;否则,返回 false。
public class Main {
public static void main(String[] args) {
char ch1 = '5';
char ch2 = 'a';
char ch3 = '!';
// 检查ch1是否是数字
if (Character.isDigit(ch1)) {
System.out.println(ch1 + " 是一个数字");
} else {
System.out.println(ch1 + " 不是一个数字");
}
// 检查ch2是否是数字
if (Character.isDigit(ch2)) {
System.out.println(ch2 + " 是一个数字");
} else {
System.out.println(ch2 + " 不是一个数字");
}
// 检查ch3是否是数字
if (Character.isDigit(ch3)) {
System.out.println(ch3 + " 是一个数字");
} else {
System.out.println(ch3 + " 不是一个数字");
}
}
}
5 是一个数字
a 不是一个数字
! 不是一个数字
Character.isDigit 方法能够准确地判断给定的字符是否为数字。这是因为它内部使用了字符的Unicode值来进行比较,而 ‘0’ 到 ‘9’ 的Unicode值恰好是连续的,且可以被轻松地识别出来。
N个数的排序与查
从键盘输入N个整数,并输出指定的某个整数在这N个整数中的按照由小到大的顺序排列的位次(最小的位次是1,最大的位次是N,指定的整数如果不在这N个数中,则其位次是-1)
输入格式: 整数个数,指定的整数值
输出格式: 指定的整数的位次
输入样例: 在这里给出一组输入。例如: 3 12 4 7 4
输出样例: 在这里给出相应的输出。例如: 1
import java.util.Scanner; // 导入Scanner类,用于接收用户输入
public class Main { // 定义一个名为Main的公共类
public static void main(String[] args) { // 主方法,程序的入口点
Scanner in = new Scanner(System.in); // 创建一个Scanner对象in,用于从标准输入(通常是键盘)读取数据
int a = in.nextInt(); // 读取用户输入的第一个整数,作为数组的长度
int[] b = new int[a]; // 根据用户输入的长度a,创建一个整型数组b
// 使用for循环读取用户输入的数组元素
for (int i = 0; i < a; i++) {
b[i] = in.nextInt(); // 读取用户输入的下一个整数,并将其存储在数组b的索引i处
}
int c = in.nextInt(); // 读取用户输入的另一个整数c,作为要查找的元素
// 使用冒泡排序算法对数组b进行升序排序
for (int m = 0; m < a - 1; m++) {
for (int i = 0; i < a - m - 1; i++) {
if (b[i] > b[i + 1]) { // 如果当前元素大于下一个元素
int temp = b[i]; // 交换两个元素的位置
b[i] = b[i + 1];
b[i + 1] = temp;
}
}
}
int j = -1; // 初始化变量j为-1,用于表示如果未找到元素c,则输出-1
// 使用for循环查找元素c在数组b中的位置
for (int m = 0; m < a; m++) {
if (c == b[m]) { // 如果当前元素等于c
j = m + 1; // 更新j为当前元素的索引+1(因为索引从0开始,而题目要求从1开始计数)
break; // 找到后退出循环
}
}
System.out.println(j); // 输出变量j的值,即元素c在数组b中的位置(如果找到的话),或者-1(如果未找到)
}
}
冒泡排序(Bubble Sort) 是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序算法的工作原理如下:
比较相邻的元素。如果第一个比第二个大(升序排序),就交换它们两个;
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数;
针对所有的元素重复以上的步骤,除了最后一个;
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
下面是冒泡排序的一个基本实现(Java语言):
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
boolean swapped;
for (int i = 0; i < n - 1; i++) {
swapped = false;
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换 arr[j+1] 和 arr[j]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
// 如果在这一趟遍历中没有发生交换,说明数组已经有序,可以提前结束
if (!swapped)
break;
}
}
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(arr);
System.out.println("Sorted array: ");
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
System.out.println();
}
}
在这个实现中,我们添加了一个swapped标志,用于检查在一次遍历中是否发生了交换。如果没有发生交换,这意味着数组已经是有序的,因此可以提前结束排序过程。这是一个优化,可以在最好的情况下(即数组已经是有序的)将时间复杂度降低到O(n)。然而,在最坏的情况下(即数组完全逆序),时间复杂度仍然是O(n^2)。
期末编程作业计分规则
PTA上的题目集的排名页以总分(满分不一定是100分)的形式按排名顺序显示每个同学的成绩,但相同分数的同学无论排名是靠前还是最后得分都是一样的。为了表示排名区分度,根据排名给出了一个简单的计分规则,以示有所区分。计分规则如下:
成绩折合成100分(取整),然后将班级人数按输入的百分比分成四个个档(如前三档人数的百分比分别为10%、40%、40%,则输入10、40
、40,各档人数均向上取整,剩下的则为最后一档人数),给出一个减分序列,每档所要减去的分数为减分序列中对应的位置及之前的值的总和。
如一个班级有10个同学,若得分都是100分,减分序列为1、3、2、2,若按10%、40%、40%的人数比例的排名分别减去1分、4分、6分、8分。这样每个同学最后的总分得分依次为:100、96、96、96、96、94、94、94、94、92。
要求编程实现根据上述计分规则计算后的成绩得分,按原排名先后输出每个同学的百分制最后得分。输入格式:
输入四行,第一行输入班级人数和满分分数,第二行按排名顺序输入每个同学的分数,第三行输入各档分数的人数百分比(三项),第四行输入减分序列。输出格式: 输出根据计分规则计算后的百分制得分,两个成绩之间以两个空格隔开
注意:最后一个数后面有两个空格
输入样例1: 在这里给出一组输入。例如: 10 100 100 100 100 100 100 100 100 100 100 100 10
40 40 1 3 2 2输出样例1: 在这里给出相应的输出。例如: 99 96 96 96 96 94 94 94 94 92
输入样例2: 在这里给出一组输入。例如: 7 120 110 95 95 92 92 92 88 10 20 40 0 1 1 1
输出样例2: 在这里给出相应的输出。例如: 91 78 78 74 74 74 70
import java.util.Scanner; // 导入Scanner类,用于从标准输入读取数据
public class Main { // 定义一个公共类Main
public static void main(String[] args) { // 主方法,程序的入口点
Scanner scanner = new Scanner(System.in); // 创建一个Scanner对象,用于读取标准输入
// 输入班级人数和满分分数
int numStudents = scanner.nextInt(); // 读取班级人数
int fullScore = scanner.nextInt(); // 读取满分分数
// 输入每个同学的分数
int[] scores = new int[numStudents]; // 创建一个整型数组,用于存储每个学生的分数
for (int i = 0; i < numStudents; i++) { // 遍历数组,为每个学生的分数赋值
scores[i] = scanner.nextInt(); // 读取每个学生的分数
}
// 输入各档分数的人数百分比
int[] percentage = new int[4]; // 创建一个整型数组,用于存储各档的人数百分比
for (int i = 0; i < 3; i++) { // 遍历数组,为各档的人数百分比赋值
percentage[i] = scanner.nextInt(); // 读取每个档的人数百分比
}
// 输入减分序列
int[] deduction = new int[4]; // 创建一个整型数组,用于存储减分序列
for (int i = 0; i < 4; i++) { // 遍历数组,为减分序列赋值
deduction[i] = scanner.nextInt(); // 读取每个减分数
}
// 计算每个同学的最终得分
int[] finalScores = calculateFinalScores(numStudents, fullScore, scores, percentage, deduction); // 调用方法计算每个学生的最终得分
// 输出最终得分
for (int i = 0; i < numStudents; i++) { // 遍历数组,输出每个学生的最终得分
System.out.print(finalScores[i] + " "); // 打印每个学生的最终得分,后跟两个空格
}
System.out.println(); // 打印换行符,结束输出
}
// 计算每个同学的最终得分
private static int[] calculateFinalScores(int numStudents, int fullScore, int[] scores, int[] percentage, int[] deduction) { // 定义一个私有静态方法,用于计算每个学生的最终得分
int[] finalScores = new int[numStudents]; // 创建一个整型数组,用于存储每个学生的最终得分
// 将成绩折合成100分
for (int i = 0; i < numStudents; i++) { // 遍历数组,将每个学生的分数折合成100分制
finalScores[i] = (int) Math.round(((double) scores[i] / fullScore) * 100); // 计算每个学生的折合分数,并四舍五入
}
// 计算各档人数
int[] tierSizes = calculateTierSizes(numStudents, percentage); // 调用方法计算各档人数
// 计算每个同学的减分
int currentDeduction = 0; // 初始化当前减分数为0
int tierIndex = 0; // 初始化当前档次索引为0
int currentTierSize = tierSizes[tierIndex]; // 初始化当前档次的人数
for (int i = 0; i < numStudents; i++) { // 遍历数组,计算每个学生的减分
if (i < currentTierSize) { // 如果当前学生在当前档次内
finalScores[i] -= currentDeduction; // 从学生的折合分数中减去当前减分数
} else { // 如果当前学生不在当前档次内
tierIndex++; // 移到下一个档次
currentTierSize += tierSizes[tierIndex]; // 更新当前档次的人数(这里应该是错误的,因为currentTierSize应该只存储当前档次的学生数)
currentDeduction += deduction[tierIndex]; // 更新当前减分数
finalScores[i] -= currentDeduction; // 从学生的折合分数中减去更新后的减分数
}
}
return finalScores; // 返回存储每个学生最终得分的数组
}
// 计算各档人数
private static int[] calculateTierSizes(int numStudents, int[] percentage) { // 定义一个私有静态方法,用于计算各档人数
int[] tierSizes = new int[4]; // 创建一个整型数组,用于存储各档人数(这里分配了4个元素,但percentage可能只有3个元素)
int remainingStudents = numStudents; // 初始化剩余学生数为班级总人数
for (int i = 0; i < 3; i++) { // 遍历percentage数组(但只到第3个元素)
tierSizes[i] = (int) Math.ceil(((double) percentage[i] / 100) * numStudents); // 计算当前档次的学生数,并向上取整
remainingStudents -= tierSizes[i]; // 更新剩余学生数
}
tierSizes[3] = remainingStudents; // 将剩余学生数分配给最后一个档次
return tierSizes; // 返回存储各档人数的数组
}
}
二维方阵变变变
有4行,4列的数据组成的矩阵。
1 2 3 45 6 7 8
9 10 11 12
13 14 15 16
它经过顺时针90度旋转后的效果为:(旋转角度值设为 90 )
13 9 5 114 10 6 2
15 11 7 3
16 12 8 4
顺时针180度旋转后的效果为:(旋转角度值设为 180 )
16 15 14 1312 11 10 9
8 7 6 5
4 3 2 1
逆时针90度旋转后的结果为:(旋转角度值设为 -90 )
4 8 12 163 7 11 15
2 6 10 14
1 5 9 13
输入格式: 首行包括:(1)二维矩阵的行(列)数n,(2)矩阵旋转的角度,从90、180、-90中取一个;
接下来是n行n列的整数,数据之间以空格分隔,组成一个方阵。输出格式: 矩阵按指定角度旋转后的结果。输出时按行、列进行组织。每行的数据之间有一个空格;行末尾数据后没有空格。
输入样例1:
4 901 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
输出样例1:
13 9 5 114 10 6 2
15 11 7 3
16 12 8 4
输入样例2:
4 1801 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
输出样例2:
16 15 14 1312 11 10 9
8 7 6 5
4 3 2 1
输入样例3:
4 -901 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
输出样例3:
4 8 12 163 7 11 15
2 6 10 14
1 5 9 13
import java.util.Scanner; // 导入Scanner类,用于接收用户输入
public class Main { // 定义一个名为Main的公共类
public static void main (String[] args) { // 主方法的定义,程序的入口点
Scanner sc=new Scanner(System.in); // 创建一个Scanner对象sc,用于从标准输入(键盘)读取数据
int n=sc.nextInt(); // 读取一个整数n,表示矩阵的维度(n*n)
int du=sc.nextInt(); // 读取一个整数du,表示旋转的度数
sc.nextLine(); // 读取并丢弃输入中的当前行剩余部分,主要是用来消耗掉输入整数后的换行符
int[][] arr=new int[n][n]; // 根据n的值,初始化一个n*n的二维数组arr
int i,j; // 声明两个整型变量i和j,用于循环遍历二维数组
for(i=0;i<n;i++) // 外层循环,遍历矩阵的行
for(j=0;j<n;j++) // 内层循环,遍历矩阵的列
arr[i][j]=sc.nextInt(); // 读取输入值并赋值给二维数组arr的相应位置
// 根据旋转度数du的值,执行不同的旋转操作
if(du==90) // 如果旋转度数为90度
for(j=0;j<n;j++) // 遍历列
{
for(i=n-1;i>0;i--) // 从倒数第二行开始向上遍历行
System.out.print(arr[i][j]+" "); // 打印当前元素后跟一个空格
System.out.println(arr[0][j]); // 打印第一行的元素,并换行
}
else if(du==180) // 如果旋转度数为180度
for(i=n-1;i>=0;i--){ // 从最后一行开始向下遍历行
for(j=n-1;j>0;j--) // 从倒数第二列开始向左遍历列
System.out.print(arr[i][j]+" "); // 打印当前元素后跟一个空格
System.out.println(arr[i][0]); // 打印当前行的第一列元素,并换行
// 注意:这里的缩进和括号使用可能导致误解,原意是在内层循环结束后换行
}
else // 如果旋转度数不是90度或180度(这里默认是270度或未指定,但代码只处理了270度的情况)
for(j=n-1;j>=0;j--) // 遍历列,从最后一列开始
{
for(i=0;i<n-1;i++) // 遍历行,但不包括最后一行
System.out.print(arr[i][j]+" "); // 打印当前元素后跟一个空格
System.out.println(arr[n-1][j]); // 打印最后一行的当前列元素,并换行
}
}
}