原视频见央视节目:
[2024央视春晚]魔术《守岁共此时》 表演:刘谦(字幕版)
该魔术背后的数学原理,可通过链表的插入、删除实现。
先提前展示运行结果:
原始牌:[方块2, 方块7, 方块6, 红桃5]
洗牌之后:[红桃5, 方块7, 方块2, 方块6]
撕成一半之后的牌:红桃5:1 方块7:1 方块2:1 方块6:1 红桃5:2 方块7:2 方块2:2 方块6:2
移动名字长度的牌至牌底:方块2:1 方块6:1 红桃5:2 方块7:2 方块2:2 方块6:2 红桃5:1 方块7:1
将前3张牌放置牌堆中间:方块7:2 方块2:2 方块6:2 方块2:1 方块6:1 红桃5:2 红桃5:1 方块7:1
将牌收藏起来: 方块7:2
南方人将前1张牌放置牌堆中间:方块6:2 方块2:1 方块6:1 红桃5:2 红桃5:1 方块2:2 方块7:1
男性将前1扔掉: 方块2:1 方块6:1 红桃5:2 红桃5:1 方块2:2 方块7:1
执行见证奇迹的时刻循环后: 方块6:1 红桃5:2 红桃5:1 方块2:2 方块7:1 方块2:1
最后一张牌为:方块7:1
原代码:
import org.apache.commons.lang3.ArrayUtils;
import java.util.Arrays;
public class LiuQianMagic {
public static void main(String[] args) {
LiuQianMagic liuQianMagic = new LiuQianMagic();
String[] oriCardArr = liuQianMagic.generateOriCardArr("方块2", "方块7", "方块6", "红桃5");
System.out.println("原始牌:" + Arrays.toString(oriCardArr));
ArrayUtils.shuffle(oriCardArr);
System.out.println("洗牌之后:" + Arrays.toString(oriCardArr));
System.out.print("撕成一半之后的牌:");
Node head = liuQianMagic.generateCutCardLinkedList(oriCardArr);
liuQianMagic.printLinkedList(head);
String yourName = "刘谦";
Node newHead = liuQianMagic.movedToEnd(head, yourName);
System.out.print("移动名字长度的牌至牌底:");
liuQianMagic.printLinkedList(newHead);
// pos为插入的牌堆位置:需要大于等于3, 小于等于7
int pos = 5;
System.out.print("将前3张牌放置牌堆中间:");
Node<Card> newHead2 = liuQianMagic.pickFirstMultiCardAndInsert(newHead, pos, 3);
liuQianMagic.printLinkedList(newHead2);
Card card = newHead2.card;
System.out.println("将牌收藏起来: " + card);
Node newHead3 = liuQianMagic.deleteFirstNode(newHead2);
// 地域: 南方人
Region region = Region.SOUTH;
System.out.print(region.regionName + "将前" + region.cardNum + "张牌放置牌堆中间:");
Node newHead4 = liuQianMagic.pickFirstMultiCardAndInsertByRegion(newHead3, pos, region);
liuQianMagic.printLinkedList(newHead4);
// 性别:男
Gender gender = Gender.MALE;
Node newHead5 = liuQianMagic.deleteFirstMultiNodeByGender(newHead4, gender);
System.out.print(gender.genderName + "将前" + gender.carNum + "扔掉: ");
liuQianMagic.printLinkedList(newHead5);
// 执行见证奇迹的时刻
Node newHead6 = liuQianMagic.movedToEnd(newHead5, "见证奇迹的时刻");
System.out.print("执行见证奇迹的时刻循环后: ");
liuQianMagic.printLinkedList(newHead6);
// 从牌堆顶将一张牌放在牌堆底, 再扔掉牌堆顶的一张牌。重复以上,直到只剩一张牌。
Card cardEnd = liuQianMagic.moveAndDropCard(newHead6);
System.out.println("最后一张牌为:" + cardEnd);
}
private Node head;
private String[] generateOriCardArr(String a, String b, String c, String d) {
return new String[]{a, b, c, d};
}
private Node<Card> generateCutCardLinkedList(String[] oriCardArr) {
this.head = new Node(new Card(oriCardArr[0], 1));
Node node1 = new Node(new Card(oriCardArr[1], 1));
Node node2 = new Node(new Card(oriCardArr[2], 1));
Node node3 = new Node(new Card(oriCardArr[3], 1));
Node node4 = new Node(new Card(oriCardArr[0], 2));
Node node5 = new Node(new Card(oriCardArr[1], 2));
Node node6 = new Node(new Card(oriCardArr[2], 2));
Node node7 = new Node(new Card(oriCardArr[3], 2));
head.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
return head;
}
public Node pickFirstMultiCardAndInsert(Node head, int pos, int carNum){
insertCard(head, pos, carNum);
Node newHead = deleteFirstMultiNode(head, carNum);
return newHead;
}
public Node pickFirstMultiCardAndInsertByRegion(Node head, int pos, Region region){
Node newHead = pickFirstMultiCardAndInsert(head, pos, region.cardNum);
return newHead;
}
public Card moveAndDropCard(Node head) {
Node<Card> current = head;
Node<Card> newHead;
Node<Card> newHead2;
while (current.next != null) {
newHead = movedToEnd(current, "1");
current = newHead;
if (current.next != null) {
newHead2 = deleteFirstNode(newHead);
current = newHead2;
}
}
return current.card;
}
// 在中间某位置插入N张卡
public void insertCard(Node head, int pos, int carNum) {
if (pos < carNum) {
System.out.println("pos需要大于等于3, 小于等于7");
System.exit(1);
}
Node<Card> current = head; // 从头开始查找最后一个节点
for (int i = 0; i < carNum; i++) {
insert(head, current.card, pos);
current = current.next;
pos++;
}
}
public Node deleteFirstMultiNode(Node head, int carNum) {
for (int i = 0; i < carNum; i++) {
head = deleteFirstNode(head);
}
return head;
}
public Node deleteFirstMultiNodeByGender(Node head, Gender gender) {
for (int i = 0; i < gender.carNum; i++) {
head = deleteFirstNode(head);
}
return head;
}
private Node<Card> movedToEnd(Node head, String name) {
int nameLen = name.length();
// System.out.println(name + ": 有" + nameLen + "个字");
if (head == null || head.next == null || nameLen <= 0) {
return head;
}
Node<Card> newHead = null;
Node<Card> curNode = head;
for (int i = 0; i < nameLen; i++) {
addToEnd(head, curNode.card);
newHead = deleteFirstNode(head);
curNode = curNode.next;
head = newHead;
}
return newHead;
}
public void addToEnd(Node head, Card card){
Node newNode = new Node(card); // 创建新的节点对象
Node current = head; // 从头开始查找最后一个节点
while (current.next != null){
current = current.next;
}
current.setNext(newNode); // 将新节点连接到当前节点的下一个位置
}
// 插入某个位置
public void insert(Node head, Card card, int pos){
int len = getLinkedListLength(head);
if (pos >= len) {
System.out.println("超出长度,插入失败");
return;
}
Node newNode = new Node(card); // 创建新的节点对象
Node current = head; // 从头开始查找
for (int i = 0; i < pos; i++) {
current = current.next;
}
Node<Card> nextNode = current.next;
current.setNext(newNode);
newNode.setNext(nextNode);
}
public Node deleteFirstNode(Node head) {
head = head.next;
return head;
}
private int getLinkedListLength(Node head) {
int len = 1;
Node curNode = head;
while(curNode.next != null) {
len++;
curNode = curNode.next;
}
return len;
}
private void printLinkedList(Node head) {
Node curNode = head;
while (curNode.next != null) {
System.out.print(curNode.card + " ");
curNode = curNode.next;
}
System.out.print(curNode.card);
System.out.println();
}
class Card {
String cardName;
int cardSign;
Card(String cardName, int cardSign) {
this.cardName = cardName;
this.cardSign = cardSign;
}
@Override
public String toString() {
return cardName + ":" + String.valueOf(cardSign);
}
}
class Node<Card> {
Card card;
Node next;
Node(Card card) {
this.card = card;
}
void setNext(Node next) {
this.next = next;
}
}
enum Region {
NORTH("北方人", 2), SOUTH("南方人", 1), UNKOWN("未知", 3);
private String regionName;
private int cardNum;
Region(String regionName, int cardNum) {
this.regionName = regionName;
this.cardNum = cardNum;
}
}
enum Gender{
MALE("男性", 1), FEMALE("女性", 2);
private String genderName;
private int carNum;
Gender(String genderName, int carNum) {
this.genderName = genderName;
this.carNum = carNum;
}
}
}