棧和隊列的面試題Java


棧和隊列:

  面試的時候,棧和隊列經常會成對出現來考察。本文包含棧和隊列的如下考試內容:

  (1)棧的創建

  (2)隊列的創建

  (3)兩個棧實現一個隊列

  (4)兩個隊列實現一個棧

  (5)設計含最小函數min()的棧,要求min、push、pop、的時間復雜度都是O(1)

  (6)判斷棧的push和pop序列是否一致

1. 棧的創建:

我們接下來通過鏈表的形式來創建棧,方便擴充。

代碼實現:

 1 public class Stack {
 2 
 3     public Node head;
 4     public Node current;
 5 
 6 
 7     //方法:入棧操作
 8     public void push(int data) {
 9         if (head == null) {
10             head = new Node(data);
11             current = head;
12         } else {
13             Node node = new Node(data);
14             node.pre = current;//current結點將作為當前結點的前驅結點
15             current = node;  //讓current結點永遠指向新添加的那個結點
16         }
17     }
18 
19     public Node pop() {
20         if (current == null) {
21             return null;
22         }
23 
24         Node node = current; // current結點是我們要出棧的結點
25         current = current.pre;  //每出棧一個結點后,current后退一位
26         return node;
27 
28     }
29 
30 
31     class Node {
32         int data;
33         Node pre;  //我們需要知道當前結點的前一個結點
34 
35         public Node(int data) {
36             this.data = data;
37         }
38     }
39 
40 
41     public static void main(String[] args) {
42 
43         Stack stack = new Stack();
44         stack.push(1);
45         stack.push(2);
46         stack.push(3);
47 
48         System.out.println(stack.pop().data);
49         System.out.println(stack.pop().data);
50         System.out.println(stack.pop().data);
51     }
52 
53 }

入棧操作時,14、15行代碼是關鍵。

運行效果:

result

2. 隊列的創建:

  隊列的創建有兩種形式:基於數組結構實現(順序隊列)、基於鏈表結構實現(鏈式隊列)。

  我們接下來通過鏈表的形式來創建隊列,這樣的話,隊列在擴充時會比較方便。隊列在出隊時,從頭結點head開始。

代碼實現:

入棧時,和在普通的鏈表中添加結點的操作是一樣的;出隊時,出的永遠都是head結點。

 1 public class Queue {
 2     public Node head;
 3     public Node curent;
 4 
 5     //方法:鏈表中添加結點
 6     public void add(int data) {
 7         if (head == null) {
 8             head = new Node(data);
 9             curent = head;
10         } else {
11             curent.next = new Node(data);
12             curent = curent.next;
13         }
14     }
15 
16     //方法:出隊操作
17     public int pop() throws Exception {
18         if (head == null) {
19             throw new Exception("隊列為空");
20         }
21 
22         Node node = head;  //node結點就是我們要出隊的結點
23         head = head.next; //出隊之后,head指針向下移
24 
25         return node.data;
26 
27     }
28 
29 
30     class Node {
31         int data;
32         Node next;
33 
34         public Node(int data) {
35             this.data = data;
36         }
37     }
38 
39 
40     public static void main(String[] args) throws Exception {
41         Queue queue = new Queue();
42         //入隊操作
43         for (int i = 0; i < 5; i++) {
44             queue.add(i);
45         }
46 
47         //出隊操作
48         System.out.println(queue.pop());
49         System.out.println(queue.pop());
50         System.out.println(queue.pop());
51 
52     }
53 }

運行效果:

result

3. 兩個棧實現一個隊列:

思路:

棧1用於存儲元素,棧2用於彈出元素,負負得正。

用棧1負責來添加操作,用棧2來實現彈出操作;如果棧2里面有元素,直接彈出,沒有元素,判斷棧1,棧1沒有元素,返回錯誤;棧1有元素,則將棧1里面的元素都彈到棧2,然后從棧2中彈出元素。

完整版代碼實現:

 1 import java.util.Stack;

 6 public class Queue {
 7 
 8     Stack<Integer> stack1 = new Stack<Integer>();
       Stack<Integer> stack2 = new Stack<Integer>();
 10	/**
 11	 * 每次添加都往棧1里面添加
 12	 * @param node 待插入隊列中元素
 13	 */
 14	public void push(int node){
 15	    stack1.push(node);
 16	}
 17	
 18	/**
 19	 * 每次彈出都從棧2里面彈出
 20	 * @return
	 */
	public int pop(){
	    if(!stack2.isEmpty())
	        return stack2.pop();
	    if(stack1.isEmpty())
	        return -1;
	    else{
	    	while(!stack1.isEmpty())
	            stack2.push(stack1.pop());
            return stack2.pop();
            }
	}
37     public static void main(String[] args) throws Exception {
38         Queue queue = new Queue();
39         queue.push(1);
40         queue.push(2);
41         queue.push(3);
42 
43         System.out.println(queue.pop());
44 
45         queue.push(4);
46 
47         System.out.println(queue.pop());
48         System.out.println(queue.pop());
49         System.out.println(queue.pop());
50 
51     }
52 
53 }

運行效果:

result

4. 兩個隊列實現一個棧:

思路:

  將1、2、3依次入隊列一, 然后最上面的3留在隊列一,將下面的2、3入隊列二,將3出隊列一,此時隊列一空了,然后把隊列二中的所有數據入隊列一;將最上面的2留在隊列一,將下面的3入隊列二。。。依次循環。

代碼實現:

 1 import java.util.ArrayDeque;
 2 import java.util.Queue;
 3 
 
 7 public class Stack {
 8 
	Queue queue1 = new LinkedList();
	Queue queue2 = new LinkedList();
11 
12   /**
	 * 添加元素的時候向不為空的隊列中添加元素
	 * @param node
	 */
	public void push(int node){
	    if(queue2.isEmpty())
	        queue1.add(node);
	    if(queue1.isEmpty())
	        queue2.add(node);
            }
	
	/**
	 * 刪除元素的時候先將不為空的隊列的前n-1個元素添加到另外一個隊列中,然后將第n個元素刪除
	 * @return
	 */
	public int poll(){
		int temp = -1;
		if(!queue2.isEmpty()){
		while(!queue2.isEmpty()){
		    temp = (int) queue2.poll();
		    if(!queue2.isEmpty())
			queue1.add(temp);
		    }
		    return temp;
		}else if(!queue1.isEmpty()){
		    while(!queue1.isEmpty()){
		        temp = (int) queue1.poll();
		        if(!queue1.isEmpty())
    			    queue2.add(temp);
		    }
		    return temp;
		}else
		    return -1;
	}
36 
37     public static void main(String[] args) throws Exception {
38         Stack stack = new Stack();
39 
40         stack.push(1);
41         stack.push(2);
42         stack.push(3);
43 
44         System.out.println(stack.pop());
45         System.out.println(stack.pop());
46         stack.push(4);
47     }
48 }

運行效果:

result

5. 設計含最小函數min()的棧,要求min、push、pop、的時間復雜度都是O(1)。min方法的作用是:就能返回是棧中的最小值。【微信面試題】

普通思路:

  一般情況下,我們可能會這么想:利用min變量,每次添加元素時,都和min元素作比較,這樣的話,就能保證min存放的是最小值。但是這樣的話,會存在一個問題:如果最小的元素出棧了,那怎么知道剩下的元素中哪個是最小的元素呢?

改進思路:

這里需要加一個輔助棧,用空間換取時間。輔助棧中,棧頂永遠保存着當前棧中最小的數值。具體是這樣的:原棧中,每次添加一個新元素時,就和輔助棧的棧頂元素相比較,如果新元素小,就把新元素的值放到輔助棧和原棧中,如果新元素大,就把元素放到原棧中;出棧時,如果原棧跟輔助棧元素相同,都彈出,否則只彈出原棧棧頂元素

完整代碼實現:


 1 import java.util.Stack;
 2 
 6 public class MinStack {
 7 
 8    
        Stack stack = new Stack();     //定義用來存儲數據的棧
        Stack minStack = new Stack();  //定義用來存儲最小數據的棧
	    
        /**
         * 添加數據,首先是往stack棧中添加
         * 如果最小棧minStack為空,或者棧頂的元素比新添加的元素要大,則將新元素也要添加的輔助棧中
         * @param node
         */
        public void push(int node) {
            stack.push(node);
            if(minStack.isEmpty() || ((int)minStack.peek()) >= node){
            	minStack.push(node);
            }
        }
	    
        /**
         * 如果stack空,直接返回
         * 如果stack不為空,得到棧頂元素,同時將棧頂元素彈出
         * 如果最小棧的棧頂元素與stack彈出的元素相等,那么最小棧也要將其彈出
         */
        public void pop() {
            if(stack.isEmpty())
                return;
            int node = (int)stack.peek();
            stack.pop();
            if((int)minStack.peek() == node){
                minStack.pop();
            }
        }
	    
        /**
         * 查看棧頂元素
         * @return
         */
        public int top() {
            return (int)stack.peek();
        }
        
        /**
         * 查看棧的最小元素
         * @return
         */
        public int min() {
            return (int)minStack.peek();
        }
     
40     public static void main(String[] args) throws Exception {
41         MinStack stack = new MinStack();
42         stack.push(4);
43         stack.push(3);
44         stack.push(5);
45 
46         System.out.println(stack.min());
47     }
48 }

result

6、判斷棧的push和pop序列是否一致:

通俗一點講:已知一組數據1、2、3、4、5依次進棧,那么它的出棧方式有很多種,請判斷一下給出的出棧方式是否是正確的?

例如:

數據:

  1、2、3、4、5

出棧1:

  5、4、3、2、1(正確)

出棧2:

  4、5、3、2、1(正確)

出棧3:

  4、3、5、1、2(錯誤)

完整版代碼:


 1 import java.util.Stack;
 2 
 3 /**
 4  * Created by smyhvae on 2015/9/9.
 5  */
 6 public class StackTest {
 7 
 8 /**
     * 首先將特殊情況,邊界情況進行排除掉
     * 然后定義一個循環,開始遍歷第一個數組,將遍歷的每個對象往stack里面添加,
     * 如果遇到棧不為空且stack頂元素與第二個數組對應位置相等的情況,就彈棧,
     * 同時第二個數組指針后移
     * 最后判斷棧是否為空
     * @param pushA 入棧隊列
     * @param popA  出棧隊列
     * @return
     */
    public boolean isPopOrder(int[] pushA, int[] popA){
    	if(pushA == null || popA == null || pushA.length == 0 || popA.length == 0 || pushA.length != popA.length)
    		return false;
    	if(pushA.length == popA.length && pushA.length == 1)
    		return pushA[0] == popA[0];
    	Stack stack = new Stack();
    	int i = 0;
    	int j = 0;
    	int len = pushA.length;
    	while(i < len && j < len){
    		stack.push(pushA[i]);
    		++i;
    		while(!stack.isEmpty() && (int)stack.peek() == popA[j]) {
    			stack.pop();
    			++j;
    		}
    	}
    	return stack.isEmpty();
    }
24 
25     public static void main(String[] args) {
26 
27         Stack<Integer> stack = new Stack<Integer>();
28 
29         int[] data1 = {1, 2, 3, 4, 5};
30         int[] data2 = {4, 5, 3, 2, 1};
31         int[] data3 = {4, 5, 2, 3, 1};
32 
33         System.out.println(sequenseIsPop(data1, data2));
34         System.out.println(sequenseIsPop(data1, data3));
35     }
36 }

代碼比較簡潔,但也比較難理解,要仔細體會。

運行效果:

result


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM