票据查重查漏问题

题目背景

某涉密单位下发了某种票据,并要在年终全部收回。

题目描述

每张票据有唯一的 ID 号,全年所有票据的 ID 号是连续的,但 ID 的开始数码是随机选定的。因为工作人员疏忽,在录入 ID 号的时候发生了一处错误,造成了某个 ID 断号,另外一个 ID 重号。

你的任务是通过编程,找出断号的 ID 和重号的 ID。

数据保证断号不可能发生在最大和最小号。

输入格式

一个整数 N(N<100) 表示后面数据行数,接着读入 N 行数据,每行数据长度不等,是用空格分开的若干个(不大于 100100 个)正整数(不大于 105105),每个整数代表一个 ID 号。

输出格式

要求程序首先输入要求程序输出 11 行,含两个整数 m,n,用空格分隔,其中,m 表示断号 ID,n 表示重号 ID。

package 练习; 
import java.util.*; 
public class 俩 {
 public static void main(String[] args) {
 Scanner scan = new Scanner(System.in);
 int n = scan.nextInt(); 
int without = 0,more = 0;
 int x;
 List<Integer> list = new ArrayList<>(); 
for(int i = 0;i < n;i ++){
 String[] s = scan.nextLine().split(" ");
 int[] a=new int[s.length];
 for(int j = 0;j < s.length;j ++) {
 a[i]=Integer.valueOf(s[i]);
 x = a[i];
 if(! list.contains(x)) 
    list.add(x); 
 else  
     more = x; 
 } 
} 
Arrays.sort(a);
 for(int k = 0 ; k < a.length ;k ++) 
    if(a[k] != a[k - 1]) 
       without = a[k]; 
System.out.println(without + " " + more); } } 

当我把别人的循环代码生搬硬套地抄上去的时候再次基础上改了一下再加上机器人的帮助还是通过不了的代码。结果Eclipse一直报错说,a没办法被范围识别到。我去查了一下通义千问,虽然我没有看懂它说的,但是我一看代码发现了:

int[] a=new int[s.length];

每次循环都会建立新的数组a[ ],但是转念一想就算是这样的问题使得我的把所有数据存进数组a的愿景失败了,也会有最后一组a[ ]里面也有最后一行数据,于是我猜测是数组a被放在了for循环里导致的(尽管我记得好像c语言里的这样结构不会有这样的问题)。后来我把数组放在循环之前定义好这个问题就解决了。(这些其实都是后面想到了,我写博客的时候没有理清楚)

其中的

在Java中,你可以使用Integer.parseInt()Integer.valueOf()方法将字符串"123"转换为整数。以下是这两种方法的示例:

String strNumber = "123";
2int number = Integer.valueOf(strNumber);
3System.out.println(number);  // 输出:123
String strNumber = "123";
2int number = Integer.parseInt(strNumber);
3System.out.println(number);  // 输出:123

我去找了通义千问,它说:

package 练习;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class Two {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int without = Integer.MAX_VALUE, more = 0;
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            String[] s = scan.nextLine().split(" ");
            int[] a = new int[s.length];
            for (int j = 0; j < s.length; j++) {
                a[j] = Integer.parseInt(s[j]); // 修改为 a[j]
                x = a[j];
                if (!list.contains(x)) {
                    list.add(x);
                } else {
                    more = x; // 这里仅仅覆盖了 more 的值,但没有记录所有重复元素
                }
            }
        }
        Arrays.sort(a);
        for (int k = 0; k < a.length && a[k] != a[k - 1]; k++) { // 改进循环条件
            without = Math.min(without, a[k]); // 更新 without 为当前遍历到的不重复元素的最小值
        }
        System.out.println(without + " " + more);
    }
}

结果——这个错误提示表明在尝试将空字符串 ("") 转换为整数时发生了 NumberFormatException。在您的代码中,第 13 行的 Integer.valueOf(s[i]) 遇到了空字符串输入。

是的新的问题又出现了

String[] s = scan.nextLine().split(" ");
int[] a = new int[s.length];
for (int j = 0; j < s.length; j++) {
    String currentString = s[j].trim(); // 先移除前后空白字符
    if (!currentString.isEmpty()) { // 检查字符串是否为空
        a[j] = Integer.parseInt(currentString);
        x = a[j];
        if (!list.contains(x)) {
            list.add(x);
        } else {
            more = x;
        }
    } else {
        // 处理空输入,可以选择忽略、提示错误或终止程序
        System.out.println("Encountered empty input, ignoring...");
    }
}

我试着用了用这个移除前后空白字符和检查字符串是否为空的部分,问题似乎得到了解决,至少不再有同样的报错了。由于我不懂这个原理,于是我把“改好”后的代码交给AI继续修改时又错误时,后面又反复试了好几次,屡战屡败,此时我意识到搞太多自己不会的就是在凑答案了(我曾试图告诉自己,有了大概思路就能靠AI开完成“不重要”的实践部分的小细节了),凑好了当然好,但是现在凑不好,很麻烦。所以我放弃了这个思路,转而思考起最开始提取代码段的来源是否正确,实验证明我搞来的循环提取代码是没有问题的。

中间经过了一些事情在另外一篇博客那里。总而言之就是我发现

可以通过控制for循环里i的“开始条件”和“结束条件”以使得读入的数据可以免遭被清除的厄运

 int begin = 0;
    	 List<Integer> list = new ArrayList<>();
    	 scan.nextLine();
    	 for(int i = 0;i < n;i ++){
    	        String[] s = scan.nextLine().split(" ");
    		    int end = begin + s.length;
    		    int k =0;
    	        for(int j = begin ;j < end;j ++) {
    	              int x = Integer.valueOf(s[k]);
    	              if(! list.contains(x)) {
    	            	  list.add(x);
    	            	  a[j] = x;
    	              }
    	              else
    	              more = x;
    	              k ++;
    	        }
    	        begin += s.length;
    	      }

并且可以用一个简单的语句

scan.nextLine();
  1. scan.nextLine(); 这一行的作用是读取用户在上一行输入的整数行数 n 后的换行符,防止下一次调用 nextLine() 方法时跳过了第一行整数数据。(这正式之前数据报错的原因——输入了换行符号,找到问题了,而不是听信之前的话,AI还是欠调教)
  2. n就是有的题目如这一题要求第一个数是将输入数据的行数(后面会有换行符)
  3.  canner.nextLine() 方法读取一行输入时,确实会包括换行符,并且返回值中不包含换行符。换行符在读取后被丢弃,不会保留在返回的字符串中。

第二天我偶然想到把用Arraylist直接判断就行了,发现这个却在实践中发现这个方法其实只能找出重复值。但苦于无法改变加上代码的简洁性使我在另外一个类里保存了它。后来想来想去,还是只能把判断缺少数拿出来用数组来判断。

我用x接收字符串转化成的数字,然后把它赋值给数组a。由于我在for之前定义了一个数组,所以我只能指定一个较大的数组a[1000]但这是样的化有的就用不上了,于是我就不得不考虑那些我没用上的了,AI告诉我

在Java中,当你定义了一个数组但没有为其赋值时,数组的元素并不会有一个默认的数值。数组的所有元素将保持未初始化状态,也就是说,它们的值是不确定的,也可以说它们包含的是垃圾值(garbage values)。

对于基本类型数组(如int, double, char等),元素的值是随机的,取决于内存中该位置的原有内容。因此,直接访问未初始化的数组元素会导致不可预知的行为,并可能引发`NullPointerException`(如果数组引用是null)或`ArrayIndexOutOfBoundsException`(如果访问了不存在的索引)。

对于引用类型数组(如Object类型),元素的默认值是`null`,这意味着它们不会指向任何对象实例。

所以在实际编程中,一定要确保在使用数组元素之前对其进行初始化。

使用Arrays.fill()方法初始化数组为0也可以对非new初始化:

int[] array1D = new int[10];
5Arrays.fill(array1D, 0);

我发现我的时 int[ ] a = new int[1000];

于是就可以有

for(int i = 1;i < a.length ;i ++){
    		 if(a[i] == 0)
    			 continue;
    		 else if(a[i - 1] != 0 && a[i] != a[i - 1] + 1) {
    			  without = a[i] - 1;
    		      break;
    		 }
    	 }

报错、调试(错得越来越对),再解决了一个个小问题之后我终于得到了。

package 练习;
import java.util.*; 
public class 俩 {
     public static void main(String[] args) {
    	 Scanner scan = new Scanner(System.in);
    	 int[] a=new int[100];
    	 int n = scan.nextInt();
    	 int without = 0,more = 0;
    	 int begin = 0;
    	 List<Integer> list = new ArrayList<>();
    	 scan.nextLine();
    	 for(int i = 0;i < n;i ++){
    	        String[] s = scan.nextLine().split(" ");
    		    int end = begin + s.length;
    		    int k =0;
    	        for(int j = begin ;j < end;j ++) {
    	              int x = Integer.valueOf(s[k]);
    	              if(! list.contains(x)) {
    	            	  list.add(x);
    	            	  a[j] = x;
    	              }
    	              else
    	              more = x;
    	              k ++;
    	        }
    	        begin += s.length;
    	      }
    	 Arrays.sort(a);
    	 for(int i = 1;i < a.length ;i ++){
    		 if(a[i] == 0)
    			 continue;
    		 else if(a[i - 1] != 0 && a[i] != a[i - 1] + 1) {
    			  without = a[i] - 1;
    		      break;
    		 }
    	 }
         System.out.println(without + " " + more); 
  }
}

这次不再有任何问题了。通过本次经历,我获得了以下启示——当你不会的时候最好缓缓,去走走,边吃饭边想问题。还有就是模块化解决问题——不要想着用什么数据结构把问题一下解决,把问题拆开来,每次解决一个部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值