目录
题目描述
输入描述
输入为 2 行,2 个串,分别表示 A、B 双方初始手里的牌序列。我们约定,输入的串的长度不超过 30。
输入输出样例
输入
输出
题目分析:
列表+递归
AC代码(Java):
小的时候,你玩过纸牌游戏吗?
有一种叫做"拉马车"的游戏,规则很简单,却很吸引小朋友。
其规则简述如下:
假设参加游戏的小朋友是 A 和 B ,游戏开始的时候,他们得到的随机的纸牌序列如下:
A 方:[K, 8, X, K, A, 2, A, 9, 5, A]
B 方:[2, 7, K, 5, J, 5, Q, 6, K, 4]
其中的 X 表示 "10",我们忽略了纸牌的花色。
从 A 方开始,A、B双方轮流出牌。
当轮到某一方出牌时,他从自己的纸牌队列的头部拿走一张,放到桌上,并且压在最上面一张纸牌上(如果有的话)。
此例中,游戏过程:
A 出 K,B 出 2,A 出 8,B 出 7,A 出 X,此时桌上的序列为:
K,2,8,7,X
当轮到 B 出牌时,他的牌 K 与桌上的纸牌序列中的 K 相同,则把包括 K 在内的以及两个 K 之间的纸牌都赢回来,放入自己牌的队尾。注意:为了操作方便,放入牌的顺序是与桌上的顺序相反的。
此时,A、B双方的手里牌为:
A 方:[K, A, 2, A, 9, 5, A]
B 方:[5, J, 5, Q, 6, K, 4, K, X, 7, 8, 2, K]
赢牌的一方继续出牌。也就是 B 接着出 5,A 出 K,B 出 J,A 出 A,B 出 5,又赢牌了。此时桌上的序列为:
5,K,J,A,5
此时双方手里牌:
AA 方:[2, A, 9, 5, A]
BB 方:[Q, 6, K, 4, K, X, 7, 8, 2, K, 5, A, J, K, 5]
注意:更多的时候赢牌的一方并不能把桌上的牌都赢走,而是拿走相同牌点及其中间的部分。但无论如何,都是赢牌的一方继续出牌,有的时候刚一出牌又赢了,也是允许的。
当某一方出掉手里最后一张牌,但无法从桌面上赢取牌时,游戏立即结束。
对于本例的初始手牌情况下,最后 A会输掉,而 B 最后的手里牌为:
9K2A62KAX58K57KJ5
本题的任务就是已知双方初始牌序,计算游戏结束时,赢的一方手里的牌序。当游戏无法结束时,输出 -1。
示例
输入
96J5A898QA
6278A7Q973
输出
2J9A7QA6Q6889977
(1):先看数据,我们需要三个单位来存放数据,题目给出的条件已知A方和B方只需要进行第一张牌出去,手牌的最后进来,符合队列的特性(先进先出)。所以双方的手牌可以用队列来存储。因为我个人习惯用列表,所以我就用列表来做。
(2):再看桌上的纸牌(下面统一用中间牌堆来表示),每次从A or B的手牌里面拿到第一张,添加到末尾,也符合队列的特性,但是它要频繁的截取一段出来,然后添加到A or B的后面,所以还是选择了使用列表来处理 中间牌堆 ,这样方便添加和取出。
(3):关于输入的数据,需要注意,当任意一方发牌结束之后,也就是往中间牌堆放牌,放完牌之后如果没有得到牌(也就是中间牌堆中没有由两个相同字符组成的字段(如K 2 7 8 X K)),那么就要结束循环,而不用另一方接着放牌(我做题的时候没有考虑这点,以为是A放完牌之后B接着放牌,这两个放完之后才考虑是否为空的情况,结果错了)。
然后看步骤
题目要求是A先放牌,然后判断中间牌堆里面有没有和A放入的牌相同的牌,如果有,那么就将牌放进去,然后找到这张牌第一次出现的次数,然后将这一段字符(如7 K 2 7 8 X K这段相同字符段就是K 2 7 8 X K)取反,在添加到A里面,然后A继续出牌。B也是同理。
出牌就可以用循环来控制和检测A和B的出牌,出牌完之后,就进行判断中间牌堆里面是否包含该牌,如果包含,就将包含的字段取反添加到他们的后面,然后继续调用出牌的方法(算递归吧?~)
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
//创建一个中间列表,用来存放A,B的出牌
static List result = new ArrayList<>();
//创建A和B的列表,用来存放他们的手牌(队列也可以)
static List A;
static List B;
public static void main(String[] args){
//拿数据
Scanner scan = new Scanner(System.in);
String s1 = scan.nextLine();
String s2 = scan.nextLine();
//通过字符串初始化列表
A = getList(s1);
B = getList(s2);
//然后循环依次往中间列表中添加数据(出牌)
//A和B都不为空的时候才继续出牌,同时定义一个res,记录循环次数,当循环太多时,就强制中断
int res = 0;
while(A.size()!=0 && B.size()!=0){
//先是A出牌,然后B出牌,如果A出牌完成了一段字符的闭合,如:K 2 7 8 X K,
//那么在方法里面会让他继续先出牌一次
dateIntoList(A);
//如果A出完牌为空了,就结束循环,B不再出牌
if(A.size()==0){
break;
}
dateIntoList(B);
//如果B出完牌为空了,也结束循环,A不再出牌
if(B.size()==0){
break;
}
//强制中断控制
res++;
if(res>100000){
System.out.println(-1);
break;
}
}
//输出部分
if(A.isEmpty()){
//如果A是空的话,就输出B
for(char ch : B){
System.out.print(ch);
}
}else{
for(char ch : A){
System.out.print(ch);
}
}
}
//往中间列表添加数据
/**
* @param list:这个出牌者当前的手牌
* */
public static void dateIntoList(List list){
//拿出第一张手牌
//list.remove方法会返回删除的数据
char c = list.remove(0);
//判断中间列表(牌堆)里面有没有跟这张牌相同的,如果有,就形成了一段闭合的字符
if(result.contains(c)){
//如果中间列表里面有这个字符,那么代表相同,将当前这个手牌添加进去
//然后调用reverse()方法将这段字符添加到对应的列表里面(根据name来判断 A or B)
result.add(c);
reverse(list,c);
}else{
//如果中间列表里面没有这个字符,那么直接添加进去就可以了
result.add(c);
}
}
//如果完成一段闭合,如K 2 7 8 X K,则将这段取反添加到出牌者后面
/**
* @param list:这个出牌者当前的手牌
* @param c:表示出现相同字段的字符
* */
public static void reverse(List list,char c){
//先拿到这个字符出现第一次的下标
int index = result.indexOf(c);
//因为要取反,所以我们从最后一个数字开始删除
while(index list = new ArrayList<>();
for(int i = 0;i