傳說中百度的試題,用C#做二進制運算得到2.5億數字中不重複數字數的O(n)算法

 using System;
using System.IO;
using System.Collections;


namespace bucketSort
{
   
class Program
    {
       
public const int maxCount = 25 * 1000 * 10000;//2.5億不算大,還沒超過整數範圍呢
        public const string FileName = @"c:/test.txt";

       
public static void Main(string[] args)
        {

           
//寫文件,用來實驗的;寫一遍就可以了;         
           
//writeFile();
           
//Console.ReadLine();
           
//return;

            FileStream  FileReader
= new FileStream(FileName, FileMode.Open);        

           
//循環讀入全部正個整數,每次讀1個整數,產生1個bit,讀到結尾標記就不讀了;

           
int index = 0;
           
//創建兩個夠長的BitArray    
           
//發現了.NET一個Bug,就是BitArray並不是可以按照int.MaxValue構造,所以限制了一下數字範圍,期待微軟能修改這個Bug。
           
//即使是在最大整數範圍內,-2,147,483,648 到 2,147,483,647是4億個Bit,1億多字節, New這兩個容器應該是2個100多M,在600M範圍內。
           
//一個數組表示有沒有這個數字

            BitArray CountorSingle
= new BitArray(250000000 + 1);

           
//第二個數組表示是否多次出現這個數字
            BitArray CountorMore = new BitArray(250000000 + 1);

           
//循環檢測,複雜度是O(N)
            while (true)
            {
               
byte[] tempByte = new byte[4];
                index
+= FileReader.Read(tempByte, 0, 4);
               
int tempInt = System.BitConverter.ToInt32(tempByte, 0);

               
if (tempInt == -1)
                {
                   
break;
                }
               
else
                {
                   
if (CountorSingle.Get(tempInt))
                    {
                       
//出現多次,設置這個值,複雜度是O(1)
                        CountorMore.Set(tempInt, true);
                    }
                   
else
                    {
                       
////出現一次,設置這個值,複雜度是O(1)
                        CountorSingle.Set(tempInt, true);
                    }
                }
            }
            FileReader.Close();

           
//從CountorSingle中排除CountorMore,採用邏輯Xor運算,複雜度是O(n)          
           
//Xor運算如果兩者值相同,爲False,1,0=1 ; 0,1=1 ; 1,1=0 ; 0,0=0  前邊已經排除了0,1的可能性。             
            CountorSingle = CountorSingle.Xor(CountorMore);//複雜度是O(n)           
           
//再讀負數那個文件。
           
           
//關鍵時刻到來了
            int sum = 0;

           
//複雜度是O(n)
            foreach (bool isExists in CountorSingle)
            {
               
if (isExists)
                {
                    sum
++;
                }
            }

            Console.WriteLine(
"全部計算複雜度是O(n),結果是:" + sum);
            Console.ReadLine();
           
//幾分鐘後,看到屏幕上顯示:全部計算複雜度是O(n),結果是:91836109


        }
       
public static long getIndex(int x)
        {
           
//int.MinValue的下標位於0,負整數n的下標是0-(long)int.MinValue;
           
//0的下標位於1-(long)int.MinValue,正整數n的下標是n+1-(long)int.MinValue;
            if (x >= 0)
            {
               
return (x + 1 - (long)int.MinValue) / 4;
            }
           
else
            {
               
return (0 - x) / 4;
            }
        }
       
public static void writeFile()
        {
           
//寫文件,用來實驗的;寫一遍就可以了,正數和零寫到正數文件裏,負數寫到負數文件裏。
           
//寫2個文件是因爲.NET的BitArray類只有構造函數是int的,如果都寫一起,那麼就超出了處理範圍。


            FileStream FileWriter
= new FileStream(FileName, FileMode.OpenOrCreate);

            System.Random rand
= new Random();
           
int i = 0;
           
for (; i < maxCount; i++)
            {
               
//寫入2.5億個整數,一個整數是4個Byte[],隨機在250000000範圍內;
               
//發現了.NET一個Bug,就是BitArray並不是可以按照int.MaxValue構造。
               
//所以就只好限制在250000000內了,先只考慮正數和0,
               
//負數可以另外改一下,放另外文件裏計算。
                int tempInt = rand.Next(0, 250000000);
                FileWriter.Write(System.BitConverter.GetBytes(tempInt),
0, 4);

            }
           
//結尾寫一個-1做標記。
            FileWriter.Write(System.BitConverter.GetBytes(-1), 0, 4);
            FileWriter.Close();
          
//靠,970多兆的文件。實驗完趕緊刪除。
            Console.WriteLine("寫文件完畢!");
        }


    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章