zoukankan      html  css  js  c++  java
  • 一个翻拍过程 翻排使用队列

    本周四同事分享了一个思维训练的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;
            }
    复制代码

    几个截图,如果题目我说得不清楚,下面几张图应该可以让大家看得更明白

  • 相关阅读:
    PAT 1010. 一元多项式求导 (25)
    PAT 1009. 说反话 (20) JAVA
    PAT 1009. 说反话 (20)
    PAT 1007. 素数对猜想 (20)
    POJ 2752 Seek the Name, Seek the Fame KMP
    POJ 2406 Power Strings KMP
    ZOJ3811 Untrusted Patrol
    Codeforces Round #265 (Div. 2) 题解
    Topcoder SRM632 DIV2 解题报告
    Topcoder SRM631 DIV2 解题报告
  • 原文地址:https://www.cnblogs.com/wei2yi/p/3248292.html
Copyright © 2011-2022 走看看