PAT(B) 1035 插入与归并(Java)
题目链接:1035 插入与归并 (25 point(s))
参考博客:PAT乙级——1035(插入排序和归并)java实现熊仙森
题目描述
根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?
输入格式
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。
输出格式
首先在第 1 行中输出Insertion Sort
表示插入排序、或Merge Sort
表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。
输入样例 1
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
输出样例 1
Insertion Sort
1 2 3 5 7 8 9 4 6 0
输入样例 2
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
输出样例 2
Merge Sort
1 2 3 8 4 5 7 9 0 6
分析💬
此题的重点是非递归的归并排序。简单描述:for
循环模拟每次取的区间范围,初始时,interval
为 1,即每 1 个元素作为一个数组,将每相邻的两个数组合并,末尾能凑够两个数组的才合并,不足两个数组的不用管。直到每次取的范围大于等于整个序列的长度时,循环结束。
注意:Java很多区间都是左闭右开的。
Java代码
/**********************************************************************************
Submit Time Status Score Problem Compiler Run Time User
8/24/2019, 17:09:33 Accepted 25 1035 Java (openjdk) 93 ms wowpH
**********************************************************************************/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
private static int[] originalSequence;// 原始序列
private static int[] middleSequence;// 中间序列
private static int length;// 序列长度,即n
private static int[] insertSort() {// 返回插入排序的结果序列或null
int[] sequence = Arrays.copyOf(originalSequence, length);// 拷贝原始序列
for (int i = 2; i < length; ++i) {
Arrays.sort(sequence, 0, i);// 前i个数排序
if (Arrays.equals(middleSequence, sequence)) {// 两序列是否相同
Arrays.sort(sequence, 0, i + 1);// 若是中间序列,继续迭代一轮
return sequence;// 返回结果序列
}
}
return null;// 不是插入排序
}
private static int[] mergeSort() {// 返回归并排序的结果序列或null
int[] sequence = Arrays.copyOf(originalSequence, length);// 拷贝原始序列
boolean flag = false;// 归并排序标志,false不是归并排序
// interval是间隔,interval=1,2,4,8,16,32,...,直到不小于原始序列的长度时结束
for (int interval = 1; !flag && interval < length; interval *= 2) {
flag = Arrays.equals(middleSequence, sequence);// 两序列是否相同
// i每次移动两个数组宽度(interval*2),直到不足两组时(一组无法合并)结束
for (int i = 0; i + interval < length; i += (interval * 2)) {
int toIndex = Math.min(i + interval * 2, length);// 区间右边界(开)
Arrays.sort(sequence, i, toIndex);// 区间[i,toIndex)排序
}
}
return (flag ? sequence : null);
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
length = Integer.parseInt(br.readLine());// 序列长度
String[] original = br.readLine().split(" ");
String[] middle = br.readLine().split(" ");
originalSequence = new int[length];// 原始序列
middleSequence = new int[length];// 中间序列
for (int i = 0; i < length; ++i) {
originalSequence[i] = Integer.parseInt(original[i]);
middleSequence[i] = Integer.parseInt(middle[i]);
}
int[] ans = insertSort();// 获取结果序列,如果不是插入排序则为null
if (null != ans) {// 不为null,则是插入排序
System.out.println("Insertion Sort");// 输出算法
} else {
System.out.println("Merge Sort");// 不是插入排序就一定是归并排序
ans = mergeSort();
}
System.out.print(ans[0]);
for (int i = 1; i < length; ++i) {
System.out.print(" " + ans[i]);
}
}
}