1 丢失的珠子
1.1 问题描述
(1) 问题描述:何老板有一盒珠子共n颗,编号1到n。他一不小心将盒子打翻,所有珠子都散落在地。他一颗一颗地把珠子捡起来,每捡一颗就记录下当前这颗珠子的编号。捡完以后发现少了两颗,请你快速找出少了哪两颗珠子。
(2) 输入格式:第一行,一个整数n;接下来一行,n-2个空格间隔的整数,表示何老板捡起来的珠子的编号。
(3) 输出格式:一行,由小到大排列的两个整数,表示丢失的两颗珠子的编号。
(4) 样例输入:
7
4 1 7 2 5
样例输出:
3 6
(5) 提示:对于30%的数据,有n<=1,000;对于100%的数据,有n<=1,000,000
(6) 基本要求:编程语言不限,提交技术报告(包括算法描述、算法的时间复杂度与空间复杂度分析、源代码、实验结果与分析)
1.2 编程实现
1.2.1 算法思想
(1)算法1:
首先将何老板捡起来的珠子编号依次存入长度为n+1的一维数组中,并且珠子编号和数组元素下标一一对应。然后再从下标1开始遍历整个数组,找到数组元素数据为0的下标,即为丢失的珠子编号。
算法1代码如下:
import java.util.*;
public class Looking_beads1 {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
int [] arr = new int[n+1];
int temp;
for(int i=1;i<n-1;i++) {
temp = sc.nextInt();
arr[temp]=temp;
}
for(int j=1;j<n+1;j++) {
if(arr[j]==0)
System.out.print(j+" ");
}
sc.close();
}
}
从上述代码中可以看出,该算法使用了一次n-1次循环和一次n次循环,因此该算法时间复杂度为O(n)。另外,该算法定义了一个一维数组,所以其空间复杂度为O(n),空间复杂度还是相对较高。下面介绍一种不使用数组的算法。
(2)算法2:
从问题描述中可以得知该串珠子的编号是有序的,那么就可以借助等差数列的思想,先求出所有珠子的编号和以及平方和,再求出n-2颗珠子的编号和以及平方和,进而得到丢失珠子的编号和以及平方和。最后利用解方程的思想得到唯一解。
算法2代码如下:
import java.util.*;
public class Looking_beads2 {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
int sum = 0;
int s_sum = 0;
int temp = 0;
for(int i=1;i<=n;i++) {
sum += i;
s_sum += i*i;
}
for(int j=1;j<=n-2;j++) {
temp = sc.nextInt();
sum -= temp;
s_sum -= temp*temp;
}
for(int k=1;k<=Math.min(sum, n);k++) {
if(k*k+(sum-k)*(sum-k) == s_sum) {
System.out.println(k+" "+(sum-k));
break;
}
}
sc.close();
}
}
从上述代码中可以看出,最坏情况下需要使用三次n次循环,所以时间复杂度还是O(n),但是由于没有使用数组,那么空间复杂度只有O(1)。算法2相较于算法1空间复杂度降低了。
1.2.2 实验结果
(1)算法2测试样例1:
7
4 1 7 2 5
测试结果如图1所示:
(2)算法2测试样例2:
20
19 8 10 9 18 12 7 4 13 15 17 6 3 1 14 16 20 2
测试结果如图2所示: