1. 程式人生 > >【面試現場】如何實現可以獲取最小值的棧?

【面試現場】如何實現可以獲取最小值的棧?

點選上方“程式人生”,選擇“置頂公眾號”

第一時間關注程式猿(媛)身邊的故事

640?wx_fmt=png

作者

channingbreeze

已獲原作者授權,如需轉載,請聯絡原作者。

小史是一個應屆生,雖然學的是電子專業,但是自己業餘時間看了很多網際網路與程式設計方面的書,一心想進BAT。

今天他又去BAT中的一家面試了。

簡單的自我介紹後,面試官給了小史一個問題。

【面試現場】

如何實現可以獲取最小值的棧

基礎資料結構靈活運用

640?wx_fmt=jpeg

題目:我現在需要實現一個棧,這個棧除了可以進行普通的push、pop操作以外,還可以進行getMin的操作,getMin方法被呼叫後,會返回當前棧的最小值,你會怎麼做呢?你可以假設棧裡面存的都是int整數。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史熟練地把程式碼寫了出來。

import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaoshi on 2018/9/1.
 */

public class MinStack {

    private List<Integer> data = new ArrayList<Integer>();
    private List<Integer> mins = new ArrayList<Integer>();

    public void push(int num) {
        data.add(num);
        if
(mins.size() == 0) {
            // 初始化mins
            mins.add(num);
        } else {
            // 輔助棧mins每次push當時最小值
            int min = getMin();
            if (num >= min) {
                mins.add(min);
            } else {
                mins.add(num);
            }
        }
    }

    public int pop
() 
{
        // 棧空,異常,返回-1
        if(data.size() == 0) {
            return -1;
        }
        // pop時兩棧同步pop
        mins.remove(mins.size() - 1);
        return data.remove(data.size() - 1);
    }

    public int getMin() {
        // 棧空,異常,返回-1
        if(mins.size() == 0) {
            return -1;
        }
        // 返回mins棧頂元素
        return mins.get(mins.size() - 1);
    }

}

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=png

【請教大神】

小史回到學校,把面試的情況和計算機學院的呂老師說了一下。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

【異常情況處理】

640?wx_fmt=jpeg

呂老師:面試官已經提出了你的異常處理有點問題,當棧內為空的時候,你返回-1,但是如果使用者push過-1,那麼你返回-1的時候,是使用者push進來的值,還是棧為空,就不得而知了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史咬咬牙:那就再定義一個類,裡面包括一個int的data和一個boolean的isSuccess,正常情況下isSuccess是true,棧為空的話,isSuccess是false。這樣就能區分開了吧?

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史突然一拍大腿:對哦,我可以用一個包裝類Integer來定義返回值,如果是空,就代表棧為空就行了。它和int的區別就是它多了一個null,正好用來返回異常情況。

640?wx_fmt=jpeg

呂老師:嗯,越來越好,但是還是有點問題。你並沒有站在使用者的角度考慮問題。使用你這個棧的人,在pop的時候,他並不知道可能返回null,如果他不做判斷,後面的程式碼就可能丟擲空指標了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

呂老師發來一個表情。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

呂老師:沒錯,最關鍵的是,你顯式丟擲異常,如果使用者不捕獲,那麼編譯就會報錯,這樣就把錯誤暴露在編譯階段,並且不需要和任何人商量所謂的特殊返回值了

640?wx_fmt=jpeg

640?wx_fmt=jpeg

【演算法優化】

640?wx_fmt=jpeg

640?wx_fmt=jpeg

呂老師一眼看穿了小史的心思。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史想了想:明白了,我可以在push的時候判斷一下,如果比最小值還大,就不加入輔助棧。pop的時候,如果不是最小值,輔助棧就不出棧。這樣一來,輔助棧就不會有大量重複元素了。

640?wx_fmt=jpeg

小史:push的時候進行判斷,如果數值比當前最小值大,就不動mins棧了,這樣mins棧中不會儲存大量冗餘的最小值。pop的時候同樣進行判斷,只有pop出的數就是當前最小值的時候,才讓mins出棧。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史:如果push一個和最小值相等的元素,還是要入mins棧。不然當這個最小值pop出去的時候。data中還會有一個最小值元素,而mins中卻已經沒有最小值元素了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史:mins棧中改存最小值在data陣列中的索引。這樣一來,當push了與最小值相同元素的時候,就不需要動mins棧了。而pop的時候,pop出的元素的索引如果不是mins棧頂元素,mins也不出棧。同時,獲取最小值的時候,需要拿到mins棧頂元素作為索引,再去data陣列中找到相應的數作為最小值。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

理解了演算法之後,小史的程式碼寫起來也是非常快,不一會兒就寫好了:

import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaoshi on 2018/9/1.
 */

public class MinStack {

    private List<Integer> data = new ArrayList<Integer>();
    private List<Integer> mins = new ArrayList<Integer>();

    public void push(int num) throws Exception {
        data.add(num);
        if(mins.size() == 0) {
            // 初始化mins
            mins.add(0);
        } else {
            // 輔助棧mins push最小值的索引
            int min = getMin();
            if (num < min) {
                mins.add(data.size() - 1);
            }
        }
    }

    public int pop() throws Exception {
        // 棧空,丟擲異常
        if(data.size() == 0) {
            throw new Exception("棧為空");
        }
        // pop時先獲取索引
        int popIndex = data.size() - 1;
        // 獲取mins棧頂元素,它是最小值索引
        int minIndex = mins.get(mins.size() - 1);
        // 如果pop出去的索引就是最小值索引,mins才出棧
        if(popIndex == minIndex) {
            mins.remove(mins.size() - 1);
        }
        return data.remove(data.size() - 1);
    }

    public int getMin() throws Exception {
        // 棧空,丟擲異常
        if(data.size() == 0) {
            throw new Exception("棧為空");
        }
        // 獲取mins棧頂元素,它是最小值索引
        int minIndex = mins.get(mins.size() - 1);
        return data.get(minIndex);
    }

}

640?wx_fmt=jpeg

640?wx_fmt=jpeg

【小史的疑惑】

吃飯的時候,小史提出了心中埋藏已久的疑惑。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

呂老師:資料結構和演算法的設計是一個程式設計師的內功,工作時雖然用不到這麼細,但是你在學習其他知識的底層原理的時候,到處都是資料結構和演算法。

640?wx_fmt=jpeg

相關推薦

面試現場如何實現可以獲取

點選上方“程式人生”,選擇“置頂公眾號”第一時間關注程式猿(媛)身邊的故事作者channingb

如何實現可以獲取

小史是一個應屆生,雖然學的是電子專業,但是自己業餘時間看了很多網際網路與程式設計方面的書,一心想進BAT。 今天他又去BAT中的一家面試了。 簡單的自我介紹後,面試官給了小史一個問題。   面試現場 題目:我現在需要實現一個棧,這個棧除了可以進行普通的pus

面試現場為什麼要分穩定排序和非穩定排序?

點選上方“程式人生”,選擇“置頂公眾號”第一時間關注程式猿(媛)身邊的故事作者channingb

做題POI2011R1 - Plot——圓覆蓋&倍增

增加 key void str ref 時間 cnblogs 答案 思路 原文鏈接 https://www.cnblogs.com/cly-none/p/loj2159.html 題意:給出\(n\)個點,你需要按編號將其劃分成不超過\(m\)段連續的區間,使得所有每個區

Java不確定參數的個數函數方法,實現

string 方法 argv 其中 span pub package values @param package 參數個數不確定方法; /** * @ClassName Test * @Description TODO * @Author cherry * @D

表中獲取,時間複雜度為O(1)

       近期複習資料結構,看到網上有一道演算法題,該題目曾經是google的一道面試題,國內的網際網路公司也紛紛效仿。我也順便複習之。        題目內容為:對現在的stack(棧)資料結構進行改進,加一個

1.給新增一個獲取的方法(元素為Integer型),要求時間複雜度為O(1)

分析:在資料結構與演算法中,當要求時間複雜度最小時基本都是要犧牲空間複雜度。棧是先進後出,此處要求用棧實現一個獲取最小值的方法且時間複雜度為O(1),首先考慮的方向就是再借助一個棧來實現,這個棧主要用來儲存最小值序列(這個地方可以思考一下為什麼不能用一個變數來儲存最小值)。 下面直接附上程式碼:   

動態規劃數字三角形(一)(遞迴)

題目:數字三角形,形如          3      3      2   4     5     1 1    3     4     1 每個點只能選擇向左或向右走,取一條路徑,使得路徑上數字和最大。 無需求出路徑,求出最大值。 輸入n,和 n 行數字三角形 n<

JavaEE筆記Struts2 (三) ognl、操作等

一. ognl概述 1. 在web階段,學習過EL表示式,EL表示式在JSP中獲取域物件裡面的值 2. ognl是一種表示式,這個表示式功能更加強大 i.在struts2裡面操作值棧資料 ii.

LeetCode-面試演算法經典-Java實現064-Minimum Path Sum(路徑和)

原題   Given a m x n grid filled with non-negative numbers, find a path from top left to botto

資料結構實現一個要求實現Push(出)Pop(入)Min(返回)的時間 複雜度為O(1)

文章目錄 思路 MinStack.h MinStack.c Test.c 棧的基本實現: https://blog.csdn.net/weixin_41892460/article/details/8297385

面試題實現一個,要求Push(入),Pop(出),Min(返回的操作)的時間複雜度為O(1)

問題描述:實現一個棧,要求Push(入棧),Pop(出棧),Min(返回最小值的操作)的時間複雜度為O(1)  分析問題:要記錄從當前棧頂到棧底元素的最小值,很容易想到用一個變數,每push一個元素更新一次變數的值。那麼問題來了,當執行pop操作時,上一次的最小值就找不到

資料結構實現一個,要求實現Push(出)、Pop(入)、Min(返回的操作)的時間複雜度為O(1)

實現一個棧,要求實現Push(出棧)、Pop(入棧)、Min(返回最小值的操作)的時間複雜度為O(1) 在棧中操作的話,push和pop的時間複雜度就是O(1),所以我們只用實現Min(返回最小值的操作)的時間複雜度為O(1), 思想就是用兩個棧,一個就是普通的存取資料的

佇列實現一個Stack,要求實現Push(出)、Pop(入)、Min(返回的操作)的時間複雜度為O(1)

問題分析 要記錄從當前棧頂到棧底元素的最小值,很容易想到用一個變數,每push一個元素更新一次變數的值。那麼問題來了,當執行pop操作時,上一次的最小值就找不到了。 解決方法 方法1、 使用一個棧。元素x入棧時,執行一次push(x),再push(min

BZOJ2424[HAOI2010]訂貨 費用流

需求 bfs pop 容量 family light 成本 pri || 【BZOJ2424】[HAOI2010]訂貨 Description 某公司估計市場在第i個月對某產品的需求量為Ui,已知在第i月該產品的訂貨單價為di,上個月月底未銷完的單位產品要付存貯費用

BZOJ1336[Balkan2002]Alien圓覆蓋 隨機增量法

tmp style i++ 5.1 logs eps light rip 個數 【BZOJ1336】[Balkan2002]Alien最小圓覆蓋 Description 給出N個點,讓你畫一個最小的包含所有點的圓。 Input 先給出點的個數N,2<

MT61含參數二次函數

tco pla 最大 back inline 我們 最小 但是 alt 評:此類題目在高考中作為壓軸題也曾考過,一般通性通法都如上面的做法,但是我們如果可以站在包絡的角度,很多問題將變得很清晰:MT【61】含參數二次函數最大最小值

十一找出一組數組中的角標、的角標及平均數

思路 原來 比較 快捷 兩個 span div 選擇排序 分數 需求:現有一組評委打分的數據。 求出他們的最大值與最小值。 最大值最小值的角標 去除最大值與最小值後的平均數 代碼: 1 <?php 2 $arr=array(1,2,3,4); 3

Codeforces 455C Civilization:樹的直徑 + 並查集合並樹後直徑

font name read amp find() edge ceil -s class 題目鏈接:http://codeforces.com/problemset/problem/455/C 題意:   給你一個森林,n個點,m條邊。   然後有t個操作。共有兩種操