剑指offer 算法(栈和队列 查找和排序)
用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素為int類型。
解析:用棧來模擬隊列。我們首先插入一個元素a到stack1中,再壓入兩個元素bc,此時棧中有元素abc,其中c位于棧頂,而stack2仍然為空。我們試著刪除一個元素。按照隊列先進先出的原則,我們應該先刪除元素a。元素a存放在stack1中且不在棧頂,因此不能直接刪除。注意到stack2還未使用,我們把stack1中的元素逐個彈出并壓入stack2中,stack2中的元素是cba,棧頂元素是a,我們現在可以直接刪除元素a了。
當stack2中不為空時,在stack2中的棧頂元素是最先進入隊列的元素,可以彈出。如果stack2為空時,我們把stack1中的元素逐個彈出并壓入stack2中。由于先進入隊列的元素被壓到stakc1的低端,經過彈出和壓入之后就處于stack2的頂端了,可以直接彈出。
題目描述
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1。
解析:例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小元素為1.
這道題最直觀的解法并不難,從頭到尾遍歷一次,我們就能找到最小的元素。這種思路的時間復雜度為O(n)。但是這個思路沒有利用輸入的旋轉數組的特性,肯定達不到面試官的要求。
我們注意到旋轉之后的數組實際上可以劃分為兩個排序的子數組,而且前面的子數組的元素都是大于或者等于后面子數組的元素。我們還注意到最小的元素剛好是這兩個子數組的分界線。在排序的數組中我們可以利用二分查找來實現O(logn)的查找。本題給出的數組在一定程度上是排序的,因此我們可以試著用二分查找的思路來尋找這個最小的元素。
以前面的例子為例,我們先把第一個指針指向第0個元素,把第二個指針指向第4個元素,如圖所示。位于兩個指針中間(在數組的下標是2)的數字是5,它大于第一個指針指向的數字。因此中間數字5一定位于第一個遞增字數組中,并且最小的數字一定位于它的后面。因此我們可以移動第一個指針讓它指向數組的中間。
此時位于這兩個指針中間的數字為1,它小于第二個指針指向的數字。因此這個中間數字為1一定位于第二個遞增子數組中,并且最小的數字一定位于它的前面或者它自己就是最小的數字。因此我們可以移動第二個指針指向兩個指針中間的元素即下標為3的元素。
此時兩個指針的距離為1,表明第一個指針已經指向了第一個遞增子數組的末尾,而第二個指針指向第二個遞增子數組的開頭。第二個子數組的第一個數字就是最小的數字,因此第二個指針指向的數字就是我們查找的結果。
技術分享
上述方法是否就一定夠完美了呢?面試官會告訴你其實不然。他將提示我們再仔細分析小標leftIndex和rightIndex分別和途中P1和P2相對應)的兩個數相同的情況。在前面,當著兩個數相同,并且它們中間的數相同的也相同時,我們把IndexMid賦給了leftIndex,也就是認為此時最小的數字位于中間數字的后面。是不是一定一樣?
我們再來看一個例子。數組{1,0,1,1,1}和數組{1,1,1,0,1}都可以堪稱遞增排序數組{0,1,1,1,1}的旋轉,圖2分別畫出它們由最小數字分隔開的兩個子數組。
技術分享
這兩種情況中,第一個指針和第二個指針指向的數字都是1,并且兩個指針中間的數字也是1,這3個數字相同。在第一種情況中,中間數字(下標為2)位于后面是子數組;在第二種情況中,中間數字(下標為2)位于前面的子數組中。因此,當兩個指針指向的數字及它們中間的數字三者相同的時候,我們無法判斷中間的數字是位于前面的子數組中還是后面的子數組中國,也無法移動兩個指針來縮小查找的范圍。此時,我們不得不采用順序查找的方法。
總結
以上是生活随笔為你收集整理的剑指offer 算法(栈和队列 查找和排序)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 剑指offer 算法(链表 树)
- 下一篇: 剑指offer 算法 (位运算)