一个翻牌算法
本周四同事分享了一个思维训练的PPT,里面有一个关于翻牌的题目,题目大致是:拿出从A到10的10张扑克牌,背面朝上摞在一起。首先把最上面的一张挪到下面,掀开新出现的一张牌是A,取出,再挪一张牌到下面,翻一张是2,依次类推,可以有顺序地翻出A到10的牌来。请问这10张牌最初是怎么排列的?看完这个题目,我当时说可以用一个算法实现。
第二天6点多醒来就一直在想这个问题,开始的时候想用递归实现,最后发现有点复杂,自己实现不了,然后想用数组实现,想法大致是这样的,先将这N个数存到数组中,然后将第一张插到最后面,第二张为A,以此类推,将每张牌经过的索引都记下来,因为每张牌最后是几是知道的,然后反推出1~N张牌是多少,但是发现记录牌经过的索引有点麻烦,效率也不高,记录的数组的第一个元素即为所求。
早上到了公司一边干活,一边实现这个算法,从题目可以很容易看出奇数位一次为1~N/2,剩下的就是求偶数位的值,马上写了个算法,运行是发现有的结果是正确的,大部分是错的,于是写了个测试方法,测试方法就很简单了,这个方法只用模拟翻牌的过程,然后输出的结果为1~N就是正确的,否则就是错误的。经测试发现我的算法思路完全是错误的,但是通过这个测试算法,我发现了能够正确实现这个题目的方法。这个题目其实不是一个递归的过程,而是一个进栈出栈的过程,奇数位进栈,偶数位出栈。我们知道最后的结果,把每张牌当做一个对象,就是进栈出栈都是以引用的方式,翻牌完成后,按顺序将它们的值一次赋值为1~N,那么我们也就知道开始的牌的顺序了,就这么简单,思路就这么简单,实现起来也就很快,于是马上实现了一个粗糙算法,最后用一个Window Form实现了,发给了同事看看,为了让大家能看得清楚,记录了翻牌的过程,当然要记录过程也是很简单的。
代码真的很简单,将每张牌当做一个对象,这样就不用记录牌经过的过程,引用类型吗!创建的对象的个数为N,过程也是线性的,不会有性能问题。
主要代码如下(代码很粗糙,但思路简单清晰,我们知道就是对的),源码下载
//将牌定义成对象 public class Card { public int Value=0 ; public override string ToString() { return Value.ToString(); } } //测试算法,记录了翻牌过程 static List<string> TestResult(Card[] arr) { if (arr == null) { throw new Exception("参数异常"); } int len = arr.Length; Queue<Card> queue = new Queue<Card>(len); foreach (Card i in arr) { queue.Enqueue(i); } List<string> list = new List<string>(len); StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { list.Add(GetItem(sb.ToString(),queue)); Card cur = queue.Dequeue(); queue.Enqueue(cur); sb.Append(queue.Dequeue().ToString().PadRight(3,' ')+" "); } return list; } static string GetItem(string s,Queue<Card> queue) { StringBuilder sb = new StringBuilder(s); foreach (var item in queue) { sb.Append(item.ToString().PadRight(3, ' ') + " "); } return sb.ToString(); } //实现翻牌的算法 static Card[] TestArr(int size) { Card[] arr = new Card[size]; for (int i = 0; i < size; i++) { arr[i] = new Card(); } int len = arr.Length; Queue<Card> queue = new Queue<Card>(len); foreach (Card i in arr) { queue.Enqueue(i); } for (int i = 1; i <= len; i++) { Card cur = queue.Dequeue(); queue.Enqueue(cur); cur = queue.Dequeue(); cur.Value = i; } return arr; }
几个截图,如果题目我说得不清楚,下面几张图应该可以让大家看得更明白