详细介绍:JAVA实验课程第五次作业分析与代码示例

1.作业内容

1.1 数组中唯一的数字

给定一个整数数组,其中除了某个元素只出现一次外,其余每个元素均出现两次。请找出那个只出现一次的元素。

1.2 验证回文串

编写一个方法,判断一个字符串是否为回文串。回文串是指正读和反读都相同的字符串,忽略字母大小写和非字母数字字符(字母和数字为有效字符)。
示例:输入:"A man, a plan, a canal: Panama"输出:true(忽略非字符后为 “amanaplanacanalpanama”,正反读相同)
输入:"race a car"输出:false

1.3字符串压缩

要求:实现一个字符串压缩算法:将连续重复的字符替换为 “字符 + 重复次数”。如果压缩后的字符串长度不小于原字符串,则返回原字符串。
示例:输入:"aabcccccaaa"输出:"a2b1c5a3"输入:"abc"输出:“abc” 解释:压缩后为 “a1b1c1”,长度更长。

1.4二维数组的转置

编写一个 Java 程序,实现二维整数数组的转置操作。转置是指将原数组的行变为列、列变为行(即原数组中位于(i,j)位置的元素,转置后位于(j,i)位置)。
注意:原数组可能不是方阵(行数和列数可以不同),转置后新数组的行数等于原数组的列数,新数组的列数等于原数组的行数。

1.5数组元素移动

编写一个 Java 程序,将整数数组中所有的 0 元素移动到数组末尾,同时保持非 0 元素的相对顺序不变。不能创建新的数组,必须在原数组上操作。

1.6数字反转与回文判断

编写程序完成两个
任务:
将一个整数反转(如 123→321,-456→-654,1200→21);
判断反转后的数字是否为回文数(即反转前后数字相同,如 121 反转后还是 121,是回文数;123 反转后是 321,不是回文数,-12321也是回文数)。

1.7 中秋国庆双节礼品分配

题目场景

中秋与国庆双节期间,班级要给同学们分配节日礼品,礼品包含 3 类:月饼礼盒、国旗徽章、中秋灯笼。已知每种礼品的总数量和班级人数,要求按以下规则分配礼品,并统计结果:
先给每位同学每种礼品各分配 1 份(确保每人都有基础礼品);
分配完基础礼品后,若某类礼品还有剩余,则按 “从第 1 位同学到最后 1 位同学” 的顺序,每人再额外分配 1 份,直到该类礼品分完(剩余不足 1 份时停止);
最后输出每位同学获得的各类礼品数量、总礼品数,以及每种礼品的剩余数量。

示例:

输入:
班级人数:5 人
礼品总数:月饼礼盒 10 份、国旗徽章 8 份、中秋灯笼 5 份
分配过程:
基础分配:每人各得 1 份月饼、1 份徽章、1 份灯笼,共消耗 5 份月饼、5 份徽章、5 份灯笼;
剩余礼品:月饼剩 5 份、徽章剩 3 份、灯笼剩 0 份;
额外分配:
月饼:按顺序给 5 人各再分 1 份,刚好分完;
徽章:按顺序给前 3 人各再分 1 份,刚好分完;
灯笼:无剩余,不分配。

2. 题目分析与解答

2.1 数组中唯一的数字

a.计数法

分析

这一道题我们要计算每个元素出现的次数,出现2次代表没问题。因此,我们只需要记录下来我们每一个元素出现的次数即可。


1.使用哈希表(HashMap)记录每个数字出现的次数,最后找出次数为 1 的数字。
2.使用一个数组记录。我们可以初始化一个全为0的数组,比如当2出现一次的时候,我们可以让arr[2]++,最后我们便利数组找出数组中值为1的下标即可。


这两种方式大家都可以尝试,但是由于我们还没有学习到哈希表,所以此处我们展示上诉第二点的代码。

代码

由于本题真正考察的是第二种解法,此处仅仅展示主要函数功能的写法,主函数放在了下一个代码中,调用的话可以模仿亦或运算中的方式调用。

public static int findUniqueNumber2(int[] nums){
int result[] = new int[100];
for (int num : nums) {
result[num]++;
}
for (int i = 0; i < result.length; i++) {
if(result[i] == 1){
return i;
}
}
return -1;
}

运行截图

在这里插入图片描述

b.亦或运算

分析:
利用异或运算的特性,相同数字异或结果为 0,0 与任何数字异或结果为该数字本身,遍历数组对所有元素进行异或操作即可得到唯一的数字。

public static void main(String[] args) {
int[] nums = {4, 1, 2, 1, 2};
System.out.println("数组中唯一的数字是: " + findUniqueNumber(nums));
// 可以添加更多测试用例
int[] nums2 = {7, 3, 5, 4, 5, 3, 4};
System.out.println("另一组测试中唯一的数字是: " + findUniqueNumber(nums2));
}
// 找出数组中唯一的数字
public static int findUniqueNumber(int[] nums) {
int result = 0;
// 利用异或运算特性:a^a=0,a^0=a,异或满足交换律和结合律
for (int num : nums) {
result ^= num;
}
return result;
}

2.2 验证回文串

分析

  • 先过滤掉非字母数字字符并转为小写。
  • 然后使用双指针从两端向中间比较,判断是否为回文串。

代码解释:

  • Character.isLetterOrDigit() 判断是否是字母或者是数字,如果不使用此方法,也可以自己写判断语句,判断某个字母是否是(字母>=‘A’ && <=‘Z’) || (字母>=‘a’ && <=‘z’ )||(字母>=‘0’ && <=‘9’ )
  • toLowerCase() 转换为小写字母。

代码

public static void main(String[] args) {
String s1 = "A man, a plan, a canal: Panama";
String s2 = "race a car";
System.out.println("\"" + s1 + "\" 是否为回文串: " + isPalindrome(s1));
System.out.println("\"" + s2 + "\" 是否为回文串: " + isPalindrome(s2));
}
// 验证回文串
public static boolean isPalindrome(String s) {
// 过滤非字母数字字符并转为小写
StringBuilder filtered = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isLetterOrDigit(c)) {
filtered.append(Character.toLowerCase(c));
}
}
// 双指针判断是否回文
int left = 0;
int right = filtered.length() - 1;
while (left < right) {
if (filtered.charAt(left) != filtered.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}

2.3 字符串压缩

分析

字符串 String还没学过,先简单看看。
根据题目意思,可以分为两部分:
-1.遍历字符串统计连续相同字符的个数,构建压缩后的字符串。
-2.最后比较压缩前后的长度,返回较短的那个。

代码

public static void main(String[] args) {
String str1 = "aabcccccaaa";
String str2 = "abc";
String str3 = "aaaaabbbbbccccc";
System.out.println("\"" + str1 + "\" 压缩后: " + compressString(str1));
System.out.println("\"" + str2 + "\" 压缩后: " + compressString(str2));
System.out.println("\"" + str3 + "\" 压缩后: " + compressString(str3));
}
// 字符串压缩
public static String compressString(String s) {
if (s.length() <= 1) {
return s;
}
StringBuilder compressed = new StringBuilder();
char current = s.charAt(0);
int count = 1;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == current) {
count++;
} else {
compressed.append(current).append(count);
current = s.charAt(i);
count = 1;
}
}
// 添加最后一组字符
compressed.append(current).append(count);
// 如果压缩后长度不小于原长度,返回原字符串
return compressed.length() < s.length() ? compressed.toString() : s;
}

2.4 二维数组的转置

分析

转置的本质是交换数组的行索引和列索引。例如原数组中matrix[i][j]的元素,在转置后的数组中会位于transposed[j][i]的位置。

代码实现

  • 实现步骤:
    首先确定原数组的行数(rows)和列数(cols);
    创建转置后的新数组,其行数为原数组的列数,列数为原数组的行数;
    通过嵌套循环遍历原数组,将每个元素放入新数组的对应位置;
    提供printMatrix方法用于打印数组,方便观察转置效果。
  • 代码:
public static void main(String[] args) {
// 测试用例1:2行3列的数组
int[][] matrix1 = {
{1, 2, 3},
{4, 5, 6}
};
System.out.println("原数组(2行3列):");
printMatrix(matrix1);
int[][] transposed1 = transpose(matrix1);
System.out.println("转置后(3行2列):");
printMatrix(transposed1);
// 测试用例2:3行3列的方阵
int[][] matrix2 = {
{10, 20, 30},
{40, 50, 60},
{70, 80, 90}
};
System.out.println("\n原数组(3行3列):");
printMatrix(matrix2);
int[][] transposed2 = transpose(matrix2);
System.out.println("转置后(3行3列):");
printMatrix(transposed2);
// 测试用例3:1行5列的数组
int[][] matrix3 = {
{1, 2, 3, 4, 5}
};
System.out.println("\n原数组(1行5列):");
printMatrix(matrix3);
int[][] transposed3 = transpose(matrix3);
System.out.println("转置后(5行1列):");
printMatrix(transposed3);
}
// 二维数组转置的核心方法
public static int[][] transpose(int[][] matrix) {
// 原数组的行数和列数
int rows = matrix.length;
// 若原数组为空,直接返回空数组
if (rows == 0) {
return new int[0][0];
}
int cols = matrix[0].length;
// 创建转置后的新数组:行数=原列数,列数=原行数
int[][] transposed = new int[cols][rows];
// 遍历原数组,填充转置后的数组
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
// 原数组(i,j)位置的元素 → 转置后(j,i)位置
transposed[j][i] = matrix[i][j];
}
}
return transposed;
}
// 辅助方法:打印二维数组
public static void printMatrix(int[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
System.out.print("[ ");
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println("]");
}
}

2.5 数组元素移动

分析

分两步操作,首先将所有非 0 元素移到前面,然后将剩余位置填充 0,确保在原数组上操作。

public static void main(String[] args) {
int[] arr1 = {0, 1, 0, 3, 12};
int[] arr2 = {0, 0, 1};
int[] arr3 = {1, 2, 3};
System.out.print("原数组1: ");
printArray(arr1);
moveZeros(arr1);
System.out.print("移动0之后: ");
printArray(arr1);
System.out.print("\n原数组2: ");
printArray(arr2);
moveZeros(arr2);
System.out.print("移动0之后: ");
printArray(arr2);
System.out.print("\n原数组3: ");
printArray(arr3);
moveZeros(arr3);
System.out.print("移动0之后: ");
printArray(arr3);
}
// 打印数组
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
if (i < arr.length - 1) {
System.out.print(", ");
}
}
System.out.println();
}
// 数组元素移动:将所有0移到末尾
public static void moveZeros(int[] nums) {
int nonZeroIndex = 0;
// 把所有非0元素移到前面
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
nums[nonZeroIndex] = nums[i];
nonZeroIndex++;
}
}
// 剩余位置填充0
for (int i = nonZeroIndex; i < nums.length; i++) {
nums[i] = 0;
}
}

提示

能不能交换,遇到0的时候就和数组最后一个数字交换。


仔细想想,是不行的,题目要求顺序不能变,这样就变顺序了。

2.6 数字反转与回文判断

分析:

处理负数情况,通过取余和乘 10 操作反转数字,最后比较原数字和反转后的数字是否相等来判断是否为回文数。

思考:是否可以使用第二题中的方式?为何不使用第二题中的方式?

代码解析:

public static void main(String[] args) {
int num1 = 12321;
int num2 = -123;
int num3 = 1200;
int num4 = -12321;
reverseAndCheckPalindrome(num1);
reverseAndCheckPalindrome(num2);
reverseAndCheckPalindrome(num3);
reverseAndCheckPalindrome(num4);
}
// 数字反转与回文判断
public static void reverseAndCheckPalindrome(int num) {
int original = num;
int reversed = 0;
boolean isNegative = num < 0;
// 处理负数
if (isNegative) {
num = -num;
}
// 反转数字
while (num != 0) {
int digit = num % 10;
reversed = reversed * 10 + digit;
num /= 10;
}
// 恢复负数
if (isNegative) {
reversed = -reversed;
}
// 判断是否为回文数
boolean isPalindrome = original == reversed;
System.out.println(original + " 反转后: " + reversed + "," +
(isPalindrome ? "是回文数" : "不是回文数"));
}

2.7 中秋国庆双节礼品分配

输出示例:

在这里插入图片描述

代码实现

public class FestivalGiftAllocator {
public static void main(String[] args) {
// 1. 定义节日相关数据:礼品名称、总数量,班级人数
String[] giftNames = {"月饼礼盒", "国旗徽章", "中秋灯笼"}; // 双节礼品类型
int[] totalGifts = {10, 8, 5}; // 每种礼品的总数量(对应上面的礼品顺序)
int studentCount = 5; // 班级人数
// 2. 创建数组存储每位同学的礼品数量:studentGifts[同学索引][礼品类型索引]
int[][] studentGifts = new int[studentCount][giftNames.length];
// 创建数组存储每种礼品的剩余数量
int[] remainingGifts = new int[giftNames.length];
// 3. 第一步:基础分配(每人每种礼品各1份)
for (int i = 0; i < giftNames.length; i++) {
// 若该类礼品总数 >= 人数,才能给每人分1份;否则无法完成基础分配(题目默认总礼品足够基础分配)
if (totalGifts[i] >= studentCount) {
for (int j = 0; j < studentCount; j++) {
studentGifts[j][i] = 1; // 每人该礼品分1份
}
// 计算基础分配后的剩余数量
remainingGifts[i] = totalGifts[i] - studentCount;
}
}
// 4. 第二步:额外分配(剩余礼品按顺序分给同学,每人每次1份)
for (int i = 0; i < giftNames.length; i++) {
// 若该类礼品有剩余,才进行额外分配
if (remainingGifts[i] > 0) {
int giftLeft = remainingGifts[i]; // 当前剩余的礼品数
int studentIndex = 0; // 从第1位同学开始(索引0)
// 循环分配,直到礼品分完或所有同学都额外分过
while (giftLeft > 0 && studentIndex < studentCount) {
studentGifts[studentIndex][i] += 1; // 给当前同学额外分1份
giftLeft -= 1; // 剩余礼品减1
studentIndex += 1; // 下一位同学
}
// 更新剩余礼品数(此时giftLeft应为0,除非礼品没分完,但题目默认可分完)
remainingGifts[i] = giftLeft;
}
}
// 5. 输出每位同学的礼品分配结果
for (int i = 0; i < studentCount; i++) {
int total = 0; // 统计当前同学的总礼品数
// 拼接该同学的各类礼品信息
StringBuilder giftInfo = new StringBuilder();
for (int j = 0; j < giftNames.length; j++) {
giftInfo.append(giftNames[j]).append(studentGifts[i][j]).append("份");
if (j < giftNames.length - 1) {
giftInfo.append(",");
}
total += studentGifts[i][j]; // 累加总礼品数
}
// 输出结果(注意:同学编号从1开始,索引从0开始,所以+1)
System.out.println("第" + (i + 1) + "位同学:" + giftInfo + ",总礼品数" + total + "份");
}
// 6. 输出剩余礼品
System.out.println("\n剩余礼品:");
for (int i = 0; i < giftNames.length; i++) {
System.out.println(giftNames[i] + ":" + remainingGifts[i] + "份");
}
}
}

posted on 2025-11-05 09:33  slgkaifa  阅读(9)  评论(0)    收藏  举报

导航