看。。。很多演算法問題都能找到它的現實原型

一線碼農發表於2014-03-16

  

  昨晚在家看 “南洋十大邪術”,又發現徐錦江了,果然是在情色片中起家的,起興處。。。被以前學校的一個小師弟抖屏攪了。。。悲劇!

由於金三銀四的好時期,小師弟也跑去找工作了,也就碰到了各種各樣的面試題,然後也就引出了今天的這篇博文,就是:如何產生1-100

之間的100個不重複的隨機數,不過這裡還好,在攜程面試.net是沒有筆試的:-)

 

     如果這是你是第一次看到這個題目,也許你的想法有很多。

 

1:首先從原始陣列中隨機選擇一個數字,然後將該數字從陣列中剔除,再隨記選,再剔除,重複99次,就解決了。

    我們知道從陣列中剔除一個元素的複雜度為O(N),那麼隨機選取n個數字,它的複雜度就是O(N2)了。

 

2:用hash作為中間過濾層,因為在陣列中,我們採用隨機數的話,也許隨機數在多次隨機中可能會有重複,所以需要用hash來判斷一下,

    如果在hash中重複,則繼續產生隨機數,直到不重複為止,當然這個複雜度就不好說了,得要看隨機數隨機不隨機了,好的話,O(N)搞定,

    不走運的話無上限~

 

3:就像標題說的一樣,很多問題我們都能在現實生活中找到寫照,畢竟很多東西是來源於現實,又抽象於現實,比如這個題目在現實生活中,

  可以對應到的就是“洗撲克牌”,在演算法中也叫“洗牌原理”,我們知道洗撲克牌的方式就是隨機的交換撲克牌的位置,又叫做"切牌",當你切了

   很多次後,我們的撲克牌就可以認為是足夠亂了,複雜度也就變成了O(N),用程式碼實現就是這樣的。

   <1> 先有序的生成52張牌,然後有序的放到陣列中。

   <2>從1-52中隨機的產生一個數,然後將當前次數的位置跟隨機數的位置進行交換,重複52次,我們的牌就可以認為足夠亂了。

 

4:程式碼實現

<1> 首先定義牌的資料結構,定義一個“花色”和“數字”

1         /// <summary>
2         /// 具體撲克牌
3         /// </summary>
4         public class Card
5         {
6             public char suit;
7 
8             public string num;
9         }

 

<2>有序的生成52張牌

 1         /// <summary>
 2         /// 開牌
 3         /// </summary>
 4         public void NewCard()
 5         {
 6             for (int i = 1; i <= card.Length; i++)
 7             {
 8                 var suit = ((i - 1) / 13) + 3;
 9                 var num = i % 13;
10 
11                 string temp;
12 
13                 switch (num)
14                 {
15                     case 1: temp = "A"; break;
16                     case 11: temp = "J"; break;
17                     case 12: temp = "Q"; break;
18                     case 0: temp = "K"; break;
19                     default: temp = num.ToString(); break;
20                 }
21 
22                 card[i - 1] = new Card()
23                 {
24                     suit = (char)suit,
25                     num = temp
26                 };
27             }
28         }

 

<3> 然後就是切牌了,剛才也說了思路,就是拿隨機數的位置與當前i的位置進行交換,不過一說到交換就想起了“氣泡排序”,可能被毒害太

  深了(┬_┬),不知道你感覺到了沒。

 1         /// <summary>
 2         /// 洗牌
 3         /// </summary>
 4         public void Shuffle()
 5         {
 6             for (int i = 0; i < card.Length; i++)
 7             {
 8                 var rand = new Random((int)DateTime.Now.Ticks).Next(0, card.Length);
 9 
10                 //因為隨機數是偽隨記,正真的隨機數是要跟硬體打交道的,所以這裡設定了停留1ms
11                 System.Threading.Thread.Sleep(1);
12 
13                 var temp = card[rand];
14 
15                 card[rand] = card[i];
16 
17                 card[i] = temp;
18             }
19         }

<4> 最後我們看看效果

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 namespace ConsoleApplication1
  8 {
  9     public class Program
 10     {
 11         static void Main(string[] args)
 12         {
 13             CardClass cc = new CardClass();
 14 
 15             cc.NewCard();
 16 
 17             Console.WriteLine("\n\n=======================洗牌之前  ===========================\n");
 18             cc.Output();
 19 
 20             Console.WriteLine("\n\n=======================洗牌之後  ===========================\n");
 21             cc.Shuffle();
 22             cc.Output();
 23 
 24 
 25             Console.Read();
 26         }
 27     }
 28 
 29     public class CardClass
 30     {
 31         public Card[] card = new Card[52];
 32 
 33         /// <summary>
 34         /// 具體撲克牌
 35         /// </summary>
 36         public class Card
 37         {
 38             public char suit;
 39 
 40             public string num;
 41         }
 42 
 43         /// <summary>
 44         /// 開牌
 45         /// </summary>
 46         public void NewCard()
 47         {
 48             for (int i = 1; i <= card.Length; i++)
 49             {
 50                 var suit = ((i - 1) / 13) + 3;
 51                 var num = i % 13;
 52 
 53                 string temp;
 54 
 55                 switch (num)
 56                 {
 57                     case 1: temp = "A"; break;
 58                     case 11: temp = "J"; break;
 59                     case 12: temp = "Q"; break;
 60                     case 0: temp = "K"; break;
 61                     default: temp = num.ToString(); break;
 62                 }
 63 
 64                 card[i - 1] = new Card()
 65                 {
 66                     suit = (char)suit,
 67                     num = temp
 68                 };
 69             }
 70         }
 71 
 72         /// <summary>
 73         /// 洗牌
 74         /// </summary>
 75         public void Shuffle()
 76         {
 77             for (int i = 0; i < card.Length; i++)
 78             {
 79                 var rand = new Random((int)DateTime.Now.Ticks).Next(0, card.Length);
 80 
 81                 //因為隨機數是偽隨記,正真的隨機數是要跟硬體打交道的,所以這裡設定了停留1ms
 82                 System.Threading.Thread.Sleep(1);
 83 
 84                 var temp = card[rand];
 85 
 86                 card[rand] = card[i];
 87 
 88                 card[i] = temp;
 89             }
 90         }
 91 
 92         /// <summary>
 93         /// 輸入牌型
 94         /// </summary>
 95         public void Output()
 96         {
 97             for (int i = 0; i < card.Length; i++)
 98             {
 99                 if (i % 13 == 0)
100                     Console.WriteLine();
101 
102                 Console.Write("{0}{1} ", card[i].suit, card[i].num);
103             }
104         }
105     }
106 }
View Code

 

其實“洗牌原理”只要說破了是很簡單的,就是你想不到,哈哈。。。然後小師弟也就明白了,我也就繼續看徐錦江的精彩表現了,o(∩_∩)o 

 

相關文章