【IT笔试面试题整理】堆栈和队列
如何準備:
Whether you are asked to implement a simple stack / queue, or you are asked to implementa modified version of one, you will have a big leg up on other candidates if you can flawlessly work with stacks and queues Practice makes perfect! Here is some skeleton code for a Stackand Queue class當面試官需要你實現(xiàn)一個簡單的堆棧或者列隊的時候,你能順利的寫完,那你就比一般的應聘者先人一步了。熟能生巧,下面的這些基本的堆棧和隊列的框架代碼一定要掌握。
Implementing a Stack堆棧
1 class Stack {2 Node top;3 Node pop() {4 if (top != null) {5 Object item = top.data;6 top = top.next;7 return item;8 }9 return null;10 }11 void push(Object item) {12 Node t = new Node(item);13 t.next = top;14 top = t;15 }16 } Implementing a Queue隊列
1 class Queue {2 Node first, last;3 void enqueue(Object item) {4 if (!first) {5 back = new Node(item);6 first = back;7 } else {8 back.next = new Node(item);9 back = back.next;10 }11 }12 Node dequeue(Node n) {13 if (front != null) {14 Object item = front.data;15 front = front.next;16 return item;17 }18 return null;19 }20 } 3 1 Describe how you could use a single array to implement three stacks3.1 怎樣用一個數(shù)組實現(xiàn)三個堆棧
3.1解答:
解法一:
將數(shù)組劃分成3等份,每一份獨立的用來實現(xiàn)堆棧。
*第一個堆棧:從 0?? ? 至 n/3
*第二個堆棧:從 n/3? 至 2n/3
*第三個堆棧:從2n/3 至 n
這種解法是基于對每個堆棧的使用沒有額外的使用說明,所以我們直接為每個堆棧劃分固定的大小。
解法二:
解法二中的,主要數(shù)組中還有空余的空間,堆棧就還能增長。
每次為堆棧分配一個空間的時候,在這個新空間中記錄上一個空間地址。這樣堆棧中的每個元素都有一個指針指向之前的元素。
這樣的實現(xiàn)方法有一個問題就是如果一個堆棧彈出一個空間(釋放空間),這個空間并不會作為空閑空間現(xiàn)在數(shù)組后面。這樣話我們就不能使用新產(chǎn)生的空閑空間。
為了解決這個問題,我們用一個列表來記錄空閑的空間。當有新空閑空間出現(xiàn),我們就把它加入到這個表中。如果需要新分配一個空間,就從這個表中刪除一個元素。
這樣的實現(xiàn)方法使得3個堆棧能夠動態(tài)的使用數(shù)組的空間,但是這是以增大空間復雜度換來的。
3.2 適合實現(xiàn)一個堆棧,除了有函數(shù)push、pop函數(shù)之外還有min函數(shù),min函數(shù)范圍堆棧中的最小元素。要求push,pop和min三個函數(shù)的時間復雜度均為O(1)。
3.2解答:
在每個堆棧中的節(jié)點中記錄目前堆棧中的最小值。那么調(diào)用min( )函數(shù)時只需要看看棧頂元素中記錄的最小值即可。
但是這樣解法存在的問題是,如果堆棧的需要記錄的元素非常多,那么這樣的方法將會消耗大量的空間。因為我們在每個堆棧的元素中都記錄來了最小值。這個能不能改進呢?
我們可以在創(chuàng)建一個輔助的堆棧只用來記錄最小的元素。
這樣的方法就是不是有更高的效率呢,在堆棧s2中只記錄最小值,避免了大量的冗余數(shù)據(jù)的記錄。
3.3 想象下啊:一堆盤子,如果堆得太高的話,就容易倒下來。所以在現(xiàn)實中如果盤子堆到一定高度,我們就會重新起一個堆。現(xiàn)在實現(xiàn)一個新的數(shù)據(jù)結(jié)構(gòu)來模擬這樣現(xiàn)象。SetOfStack當中包含很多的堆棧,當一個堆棧達到上限的時候,啟用下一個堆棧。SetOfStack.push 和 SetOfStack.pop應該和普通堆棧的操作一樣。
進階:
實現(xiàn)一個函數(shù)popAt(int index),指定在哪個堆棧上彈出元素。
3.3解答:
根據(jù)題意,我們的數(shù)據(jù)結(jié)構(gòu)大體上應該是這么一個框架:
由于要和普通的堆棧的push()有相同的效果,也就是說每次push()都必須將元素放到最近使用的一個堆棧中。但是在這個堆棧已經(jīng)滿了情況下,那就必須建一個新的堆棧然后再入棧。那么push的實現(xiàn)如下:
那pop()如何實現(xiàn)呢?和push()差不多,也一定要在最近的一個堆棧上操作。但是如果最后一個堆棧是空的話,就應該將其移除。
那進階的問題這么處理呢?
這個問題確實有點難度。實現(xiàn)起來也比較麻煩,因為整個系統(tǒng)看起來應該像一個“翻轉(zhuǎn)”系統(tǒng)。如果我從堆棧1中彈出一個元素,那么我們需要將堆棧2底部的元素壓到堆棧1的頂端。堆棧3的元素要到堆棧2....
注:你可能會不同意我的說法。認為實現(xiàn)這個函數(shù)不需要“翻轉(zhuǎn)”整個堆棧。系統(tǒng)中的每個堆棧并不需要都是滿棧的,這樣的話也可以省下很多的時間復雜度,特別是在堆棧非常大的時候。但是如果假設(shè)除了最后一個堆棧之外,所有的堆棧必須滿棧的話,這樣的方法就不行了。具體采用什么樣的結(jié)構(gòu),你可以在面試時和面試官好好溝通然后決定。
3.4 經(jīng)典的漢諾塔問題,有3根柱子,柱子上串有N個尺寸不同的碟子。漢諾塔問題的起始狀態(tài)為,所有的碟子都從小到大的穿在柱子上(下面的碟子最大)。在滿足下面三個限制:(A) 每次只能移動一個碟子;(B) 只有每根柱子頂端的碟子才能移動;(C)任何碟子只能放在比它大的碟子上。寫一段程序(要求使用堆棧),將第一個根柱子上所有的碟子移動到移到最后一根柱子上。
3.4解答:
首先我們考慮解題的算法:將N個碟子從第一根柱子移到最后一根柱子。我們先從最簡單的情況開始。如果只有一個碟子,那么直接將它移到最后的柱子。那兩個碟子呢?
(1)先將第一個碟子從第一根柱子移到第二根
(2)將第二個碟子從第一根柱子上移動到第三根
(3)再將第二根柱子上的碟子移動到第三根上,完成!
那三個碟子呢?
(1)采用兩個碟子移動的方法,講上兩個碟子移動到第二根柱子上
(2)將第三個碟子移動到第三根柱子
(3)在采用運來的方法將第二根柱子上的兩個碟子移動到第三根柱子。
很明顯采用遞歸算法就能解決本題:
3.5 用兩個堆棧來實現(xiàn)一個隊列
3.5解答:
堆棧和隊列的最大區(qū)別在于:一個是先進后出,一個是后進先出。但是題目的要求使得peek和pop的動作恰好相反。那么我們就可以利用第二個堆棧完成入棧元素順序的反轉(zhuǎn)。(先所有的元素進堆棧S1,這樣最先進棧的元素在棧底,最后的在棧頂;然后將S1中的元素依次彈出,并壓入堆棧S2中。這樣S2中先進的元素就在棧頂后進的就在棧底了。)
但是如果對隊列和出隊列的動作反復進行的話,我就要在S1和S2兩個堆棧中反復的倒來倒去。其實有偷懶的方法。
當有元素要進入隊列的時候,直接壓如堆棧S1中,元素需要從隊列中出列的話,檢查S2中是否有元素,如果沒有再采用之前的方法將S1中的元素“倒”入到S2中,如果S2中非空在直接彈出元素即為隊列中出列的元素。這樣的方法就免于在兩個堆棧之間倒來倒去了:
3.6 寫一個程序?qū)⒍褩I蚺判?。該堆棧就是一個普通的堆棧,不能有其他假設(shè)。函數(shù)實現(xiàn)是只能調(diào)用函數(shù)push(),pop(),peek()和isEmpty這幾個函數(shù)。
3.6解答:
再建一個堆棧,從原堆棧中彈出一個元素到新的堆棧中。然后再比較原堆棧棧頂元素和新堆棧棧頂大小。如果符合排序規(guī)則,再次入新堆棧。如果不符合,在彈出新堆棧中的元素逐個比較直到滿足排序關(guān)系。這樣類似插入排序的方法,之間復雜度為O(n^2)。
總結(jié)
以上是生活随笔為你收集整理的【IT笔试面试题整理】堆栈和队列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌向 Pixel Buds A 推送
- 下一篇: [二叉树]二叉搜索树转换为双向链表(剑指