1. 程式人生 > >面試題---設計包含min函式的棧

面試題---設計包含min函式的棧

題目:定義棧的資料結構,要求新增一個min函式,能夠得到棧的最小元素。要求函式min、push以及pop的時間複雜度都是O(1)。
分析:這是去年google的一道面試題。

我看到這道題目時,第一反應就是每次push一個新元素時,將棧裡所有逆序元素排序。這樣棧頂元素將是最小元素。但由於不能保證最後push進棧的元素最先出棧,這種思路設計的資料結構已經不是一個棧了。

在棧裡新增一個成員變數存放最小元素(或最小元素的位置)。每次push一個新元素進棧的時候,如果該元素比當前的最小元素還要小,則更新最小元素。

乍一看這樣思路挺好的。但仔細一想,該思路存在一個重要的問題:如果當前最小元素被pop出去,如何才能得到下一個最小元素?

因此僅僅只新增一個成員變數存放最小元素(或最小元素的位置)是不夠的。我們需要一個輔助棧。每次push一個新元素的時候,同時將最小元素(或最小元素的位置。考慮到棧元素的型別可能是複雜的資料結構,用最小元素的位置將能減少空間消耗)push到輔助棧中;每次pop一個元素出棧的時候,同時pop輔助棧。

參考程式碼:

#include <deque>
#include <assert.h>

template <typename T> class CStackWithMin
{
public:
      CStackWithMin(void) {}
      virtual ~CStackWithMin(void) {}

      T& top(void);
      const T& top(void) const;

      void push(const T& value);
      void pop(void);

      const T& min(void) const;

private:
     T> m_data;               // the elements of stack
     size_t> m_minIndex;      // the indices of minimum elements
};

// get the last element of mutable stack
template <typename T> T& CStackWithMin<T>::top()
{
      return m_data.back();
}

// get the last element of non-mutable stack
template <typename T> const T& CStackWithMin<T>::top() const
{
      return m_data.back();
}

// insert an elment at the end of stack
template <typename T> void CStackWithMin<T>::push(const T& value)
{
      // append the data into the end of m_data
      m_data.push_back(value);

      // set the index of minimum elment in m_data at the end of m_minIndex
      if(m_minIndex.size() == 0)
            m_minIndex.push_back(0);
      else
      {
            if(value < m_data[m_minIndex.back()])
                  m_minIndex.push_back(m_data.size() - 1);
            else
                  m_minIndex.push_back(m_minIndex.back());
      }
}

// erease the element at the end of stack
template <typename T> void CStackWithMin<T>::pop()
{
      // pop m_data
      m_data.pop_back();

      // pop m_minIndex
      m_minIndex.pop_back();
}

// get the minimum element of stack
template <typename T> const T& CStackWithMin<T>::min() const
{
      assert(m_data.size() > 0);
      assert(m_minIndex.size() > 0);

      return m_data[m_minIndex.back()];
}

舉個例子演示上述程式碼的執行過程:

  步驟              資料棧            輔助棧                最小值
1.push 3    3          0             3
2.push 4    3,4        0,0           3
3.push 2    3,4,2      0,0,2         2
4.push 1    3,4,2,1    0,0,2,3       1
5.pop         3,4,2      0,0,2         2
6.pop         3,4        0,0           3
7.push 0    3,4,0      0,0,2         0

討論:如果思路正確,編寫上述程式碼不是一件很難的事情。但如果能注意一些細節無疑能在面試中加分。比如我在上面的程式碼中做了如下的工作:

·         用模板類實現。如果別人的元素型別只是int型別,模板將能給面試官帶來好印象;

·         兩個版本的top函式。在很多類中,都需要提供const和非const版本的成員訪問函式;

·         min函式中assert。把程式碼寫的儘量安全是每個軟體公司對程式設計師的要求;

·         新增一些註釋。註釋既能提高程式碼的可讀性,又能增加程式碼量,何樂而不為?

總之,在面試時如果時間允許,儘量把程式碼寫的漂亮一些。說不定程式碼中的幾個小亮點就能讓自己輕鬆拿到心儀的Offer。