1. 程式人生 > >演算法 韓信點兵 迴圈左移陣列元素

演算法 韓信點兵 迴圈左移陣列元素

static void Main(string[] args)
        {
            ForeachLeft();//韓信點兵
        }
        public static void ForeachLeft()
        {
            int[] arr = new int[5] { 1, 3, 5, 8, 6 };
            int[] result = loopleft(3, arr);
            foreach (var item in result)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
        }
        
public static int[] loopleft(int n, int[] arr) { if (arr==null||arr.Length==0) { return arr; } reverse(0, n - 1, ref arr); reverse(n , arr.Length - 1, ref arr); reverse(0, arr.Length - 1, ref arr);
return arr; } public static void reverse(int left, int right, ref int[] arr) { int temp = 0; while (left < right) { temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left
++; right--; } }

自從“韓信點兵,多多益善”事件之後,韓信的麻煩事就來了。這不,今天劉邦又找他麻煩了。

 

劉邦:愛將,近日朕看你早早就下班了,怎麼回事呀?

 

韓信:陛下明鑑,臣點兵時有技巧,效率極高,陛下安排的工作任務臣均已完成。而本朝建立以來實行彈性工作制,於是臣就回家了。

 

劉邦:你小子是真不知道朕的苦衷啊!朕的大漢朝剛剛建立,百廢待興,你就不能為朕分憂,為大漢朝多做點貢獻嗎?

 

韓信:何事叨擾陛下?請陛下明示,臣必當竭盡全力!

 

劉邦心理活動:我哪有什麼事情讓你去做呀?讓你辦事只是藉口啦!只不過是擔心你下班那麼早,空閒下來謀劃策反之事罷了。不得不防啊!為了不讓你那麼早下班,是得隨便找個事拖拖你。)

 

突然,劉邦想了個法子。

 

劉邦:既然你點兵是個能手,朕就交你一事。從明天上班開始,你在點兵之前,要先將你的士兵迴圈左移,左移完畢,讓我審查,再開始點兵。

 

說著,劉邦用木棍在地上畫了起來。

 

 

 

劉邦:假如現在有7個士兵,迴圈左移3次,移動結果如上圖。

 

韓信:陛下,這好辦,在移動時,我只要先讓前三個士兵出列,然後讓後面的兵依次向前移動三個位置,最後把前三個兵插入到隊尾即可。

 

劉邦:那我如果讓你左移4次、5次,你是不是要分別出列4個、5個人呢?不行,限制你每次只能出列1個人。

(注:從演算法角度分析,這其實是限制了空間複雜度為O(1))

 

韓信心理活動:如果每次只能出列一個人的話,我就得按劉老闆畫得那樣,第一次先將1號士兵出列,然後讓其他士兵依次向前移動一個位置,最後再把1號士兵插入隊尾,對於2號、3號士兵也當如此。忽然,他想到了一個問題,在點兵前為什麼要進行左移這個活動呢?沒什麼意義呀。)

 

正當他想問劉邦,此時劉邦瞪了他一眼,於是他趕緊改變主意,回覆遵命。畢竟,快過年了,年終獎要緊。

 

就這樣,接下來的日子裡,韓信在點兵前都要進行這樣一項活動,可是,隨著時間一天天流逝,韓信發現劉老闆給他的兵越來越多了,兵少時沒關係,進行左移活動也用不了多少時間,而兵多了就麻煩了,常常使自己加班加到很晚才能下班。

 

(PS:劉老闆對韓信已有懷疑之心,可為什麼還要給他越來越多的兵呢?沒錯,他在試探韓信,當韓信擁兵眾多時會不會謀反。)

 

求助

 

無法忍受這樣無休止的加班,韓信來拜訪張良。見到張良,將自己的情況一五一十給張良道明。

 

張良:初創公司都這樣,加班是常事,習慣就好了。

 

韓信:可我覺得不是加班那麼簡單,劉老闆似乎故意在找我麻煩。

 

張良:你可知劉老闆為何要找你麻煩呀?

 

韓信:實在是無所得知啊!

 

張良:當真不知?

 

韓信:不知。

 

張良:你可知功高蓋主的道理呀?

 

韓信:你是指老闆擔心我取代他。

 

張良:是呀,外邊都在說你“韓信點兵,多多益善”,有句話“狡兔死,走狗烹,飛鳥盡,良弓藏”,你不得不記在心上呀!

 

(韓信直冒冷汗)

韓信:謹記教誨,而當務之急是先把這個士兵左移問題解決了,否則,我可能因此而被殺頭。

 

張良拿起木棍在地上畫了起來,不一會兒,有了答案。

 

張良:還拿你剛剛說的例子為例,如下圖,有7個士兵,迴圈左移3位,你可以將此問題分為3步:

  1. 將佇列分為兩部分,左移3位就從第三個士兵後面劃分;

  2. 分別對左右兩部分逆序,具體逆序過程:將第一個士兵與最後一個士兵交換位置,將第二個士兵與倒數第二個交換位置,以此類推。具體交換時,比如1號士兵與3號士兵,可以先讓1號士兵出列,3號填補到1號位置上,再把1號入列到3號位置上,這樣也滿足了劉老闆規定的每次只能出列一個士兵。

  3. 再對整個佇列進行一次逆序,完畢。

 

 

 

韓信感激涕零,覺得張良的方法效率太高了,謝過張良後,告辭了。

 

(注:韓信原來的方法時間複雜度為O(nL),張良的方法時間複雜度為O(L),其中n為移動位數,L為陣列長度)