1、问题描述
魔术师利用一副牌中的13张黑桃牌,预先将他们排好后叠放在一起,牌面朝下。对观众说:“我不看牌,只数数就可以次熬到每张牌是什么,我大声数数,你们听,不信?现场演示。”魔术师将牌堆最上面的哪张排数为1,把他翻过来正好是黑桃A,将黑桃A从牌堆抽出放在桌子上,第二次数1、2,将第一张放在牌堆最下面,第二张翻开,正好是黑桃2,也将它抽出放在桌子上。这样依次进行将13将牌全部翻出,准确无误。问牌最开始的顺序是怎样排的。
2、问题求解
创建带有13个空间点的循环链表,模拟魔术师数数翻牌,第一次翻出的位置是黑桃A,,设置链表改位置节点值为1,第二次翻出的位置是黑桃2,,设置链表改位置节点值为2,依次类推,最终可得牌最开始的排列顺序。
package test.algorithm.FastSlowPointer;
public class Magician {
public static void main(String[] args){
//创建并初始化有13个节点的链表, 0代表节点值为空
Node header = null;
Node pointer = header;
for(int i=1;i<=13;i++){
Node temp = new Magician.Node(0);
if(header==null){
header = temp;
}else{
pointer.next = temp;
}
pointer = temp;
pointer.next = header;
}
System.out.print("创建13个节点的空链表:");
printList(header);
//根据魔术师发牌逆推牌的开始顺序
pointer = header;
int countNum = 1 ;
while(true){
//按顺序查找揭牌位置
for(int i=1;i<countNum;i++){
pointer = pointer.next;
// 如果当前位置的牌已揭开,则该位置不计数
if(pointer.num!=0){
i--;
}
}
// 设置揭牌位置的点数
if(pointer.num==0){
pointer.num = countNum;
countNum++;
//设置了当前位置,指针指向下一个位置
pointer = pointer.next;
}
// 如果超出了13,跳出循环
if(countNum>13){
break;
}
}
System.out.print("牌的开始顺序:");
printList(header);
}
static class Node {
private int num;
private Node next;
public Node(int num){
this.num = num;
}
}
/**
* 打印链表
* @param node
*/
static void printList(Node header){
Node pointer = header;
do{
System.out.print(pointer.num+" ");
pointer = pointer.next;
}while(pointer!=null && pointer!=header);
System.out.println();
}
}