7-1 对称排序 (25 分)
题目源自PTA
你供职于由一群丑星作为台柱子的信天翁马戏团。你刚完成了一个程序编写,它按明星们姓名字符串的长度非降序(即当前姓名的长度至少与前一个姓名长度一样)顺序输出他们的名单。然而,你的老板不喜欢这种输出格式,提议输出的首、尾名字长度较短,而中间部分长度稍长,显得有对称性。老板说的具体办法是对已按长度排好序的名单逐对处理,将前者放于当前序列的首部,后者放在尾部。如输入样例中的第一个案例,Bo和Pat是首对名字,Jean和Kevin是第二对,余此类推。
输入格式:
输入包含若干个测试案例。每个案例的第一行含一个整数n(n>=1),表示名字串个数。接下来n行每行为一个名字串,这些串是按长度排列的。名字串中不包含空格,每个串至少包含一个字符。n=0为输入结束的标志。
输出格式:
对每一个测试案例,先输出一行“Set n”,其中n从1开始取值,表示案例序号。接着是n行名字输出,如输出样例所示。
输入样例:
7
Bo
Pat
Jean
Kevin
Claude
William
Marybeth
6
Jim
Ben
Zoe
Joey
Frederick
Annabelle
5
John
Bill
Fran
Stan
Cece
0
输出样例:
SET 1
Bo
Jean
Claude
Marybeth
William
Kevin
Pat
SET 2
Jim
Zoe
Frederick
Annabelle
Joey
Ben
SET 3
John
Fran
Cece
Stan
Bill
关键问题:
如何实现放前面一个接着放后面一个???
有没有什么东西(类)能够直接实现这个,前面放一个,后面放一个
解决问题:
不得不说Java就是牛啊,只有想不到,没有做不到,不用不知道,用了忘不掉。
初识Java数据结构,咱也不知道有什么好用的类以及方法,抱着试试的心态,开始看实现接口Queue
的相关类,找相关的方法。看到LinkedBlockingDeque<E>
这个类时,咱也不知道是什么东东,咱就知道里面有两个方法能够帮我解决上面的问题。
描述 | |
---|---|
void | putFirst(E e) 将指定的元素插入此双端队列的开头,必要时将一直等待可用空间。 |
void | putList(E e) 将指定的元素插入此双端队列的末尾,必要时将一直等待可用空间。 |
代码
import java.util.Scanner;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingDeque;
public class Main {
public static void main(String[] args) throws InterruptedException {
Scanner input = new Scanner(System.in);
LinkedBlockingDeque<Object> s = new LinkedBlockingDeque<>();
Stack<Object> swop = new Stack<Object>();//存放所有名字
int count = 1;//计数器
int sum;
while ((sum = input.nextInt()) != 0) {
for (int i = 0; i < sum; i++) {
String name = input.next();
swop.push(name);
}
//名字出栈交替存放在队头和队尾
if (sum % 2 == 0) {
for (int j = 0; j < sum; j++) {
if (j % 2 == 0) {
s.putLast(swop.pop());
} else {
s.putFirst(swop.pop());
}
}
} else {
for (int j = 0; j < sum; j++) {
if (j % 2 == 0) {
s.putFirst(swop.pop());
} else {
s.putLast(swop.pop());
}
}
}
System.out.println("SET " + count);
for (int j = 0; j < sum; j++) {
System.out.println(s.pop());
}
count++;
}
input.close();
}
}
遇到的问题及疑惑
- 为什么在不判断sum是否为奇偶直接进行交替存放时,人名个数为偶数(奇数)的时候,刚好与正确答案相反?
- 有没有别的类来替代
LinkedBlockingDeque<E>
这个类?
优化及解决疑惑
起初出于误打误撞竟然AC了,后面经过debug发现,真正的思路是:
创建一个栈,一个队列。把所有的名字按顺序存放到栈中,在出栈的时候刚好所有顺序变为名字长的在最顶端,短的放在了底端,然后出栈的时候再交替把名字一个放队头一个放队尾。
明白了上面的思路后,遇到的问题及疑惑也就迎刃而解。
- 不进行判断时,名字个数为奇数时,是不对称的,所以当为奇数时提前将栈顶元素入队列即可。
- 经过几天的学习,了解些皮毛,在Java中一般用
LinkedList
看做队列,所以可以用同样的方法解决问题。
描述 | |
---|---|
void | addFirst(E e) 将指定元素插入此列表的开头。 |
void | addLast(E e) 将指定元素添加到此列表的结尾。 |
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Stack;
public class Main2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
LinkedList<Object> s = new LinkedList<>();
Stack<Object> swap = new Stack<Object>();//存放所有名字
int count = 1;//计数器
int sum;//名字个数
while ((sum = input.nextInt()) != 0) {
for (int i = 0; i < sum; i++) {
String name = input.next();
swap.push(name);
}
if (sum % 2 != 0) {//是奇数把栈顶元素先入队列中
s.add(swap.pop());
sum = sum - 1;
}
//交替存放在队头和队尾
for (int j = 0; j < sum; j++) {
if (j % 2 == 0) {
s.addLast(swap.pop());
} else {
s.addFirst(swap.pop());
}
}
System.out.println("SET " + count);
while (!s.isEmpty()) {//打印队列中的所有元素,并逐个出栈。
System.out.println(s.pop());
}
count++;
}
input.close();
}
}
生命的道路有无数交叉小径,无论你走哪一条,愿你山穷水复之时都有柳暗花明。 ————《吞噬地球》