Stacks of Flapjacks
[问题描述]
堆栈和队列通常被认为是数据结构的面包和黄油,可用于体系结构、解析,操作系统和离散事件模拟。堆栈在形式语言理论中也很重要。
现在的问题涉及黄油和煎饼(而不是面包),同时还有一个根据唯一但完整的规则来翻煎饼的服务器。
给你一栈的煎饼,请你编写一个程序用于指示这个栈如何被排序以使得最大的煎饼在最下面而最小的煎饼在最上面。
煎饼的直径将被给出。
栈中的所有煎饼的直径都不一样。
对栈排序是通过一系列"翻转"来完成的。
一次翻转的意思是:在两个煎饼之间插入铲子,然后将铲子上面的一堆煎饼整体翻过来。也就是指定一个位置,其上的子栈整体翻转。
翻转的位置将会被给出。
位置是这样定义的:栈底编号为1,栈顶编号为n
一个栈的煎饼的给出方式,是从上到下给出煎饼的直径。
举例来说,这是三个栈,左边的栈的最上面的煎饼直径为8
8 7 2
4 6 5
6 4 8
7 8 4
5 5 6
2 2 7
左侧栈,可在位置3(即直径7)处翻转,得到中间的那个栈,而中间那个栈可在位置1(即直径2)处翻转,得到右侧的栈。
Input(输入)
输入由多个煎饼栈组成。每个栈有1到30个煎饼,每个煎饼的直径在1-100之间。以文档结束为输入结束。每个栈,独占一行,从左到右依次代表从栈顶到栈底的煎饼的直径,空格隔开。
Output(输出)
对于每个煎饼栈,输出首先应原样将栈的数据打印成一行。
随后的一行是翻转位置的次序,空格隔开,以0结束。(结束的目标是最大直径在最下面,最小直径在最上面)。
Sample Input
1 2 3 4 5
5 4 3 2 1
5 1 2 3 4
Sample Output
1 2 3 4 5
0
5 4 3 2 1
1 0
5 1 2 3 4
1 2 0
思路
其实这题本质上是一道数组排序的问题。在思考排序方法之前,应该留意题目给出的条件和提示。
- 若将这个所谓的栈看作数组,那么栈顶位置是0,栈底位置是arr.length-1
- 翻转的方式是从翻转点向栈顶的方向进行翻转
明确以上两个重要的概念之后就可以思考如何给数组排序并且记录翻转点了。事实上,以翻转的方式进行排序就是想尽办法将数组中最大的值依次放到数组的最后面(即栈底),但是要注意数组中最大值的位置有两种情况。- 最大值在0索引(栈顶),此时以栈底为翻转点翻转即可将最大值放在数组末尾。
- 最大值不在栈顶,此时以最大值所在的位置为翻转点翻转,可将最大值放在0索引,继而重复1步骤,即可将最大值放在数组末尾。
- 此时最大值在末尾,不必再考虑它,开始寻找次大的数值执行上述操作,但是操作的规模要整体减1(即忽略已经放好位置的元素)。
事实上,到了这里可以看出,这个方法的实现形式就是迭代或者递归,现在考虑迭代(递归)的终止条件是什么,前面已经提到这个问题的本质是一个排序问题,所以当整个数组完全有序时,即可退出迭代(递归)。
源代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String s = sc.nextLine();
// 填充数组
String[] str = s.split(" ");
int[] arr = new int[str.length];// 最多有30个煎饼
for (int i = 0; i < str.length; i++) {
arr[i] = Integer.parseInt(str[i]);
}
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.println(arr[i]);
break;
} else {
System.out.print(arr[i] + " ");
}
}
int len = arr.length;
StringBuilder res = new StringBuilder();
while (!isOrdered(arr, len)) {
int indexOfMax = getIndexOfMax(arr, len);
if (indexOfMax == 0) {// 最大的在顶部,翻底
res.append(arr.length - (len - 1) + " ");
resever(arr, len - 1);
len--;// 规模减1
} else {// 翻最大的
res.append(arr.length - indexOfMax + " ");
resever(arr, indexOfMax);
}
}
res.append(0);
System.out.println(res.toString());
}
}
private static boolean isOrdered(int[] arr, int length) {
for (int i = 0; i < length - 1; i++) {
if (arr[i] > arr[i + 1]) {
return false;
}
}
return true;
}
private static int getIndexOfMax(int[] arr, int length) {
int max = 0;
for (int i = 0; i < length; i++) {
if (arr[i] > arr[max]) {
max = i;
}
}
return max;
}
private static void resever(int[] arr, int end) {
int begin = 0;
while (begin < end) {
swap(arr, begin, end);
begin++;
end--;
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}