1. 程式人生 > >棧、佇列面試題總結

棧、佇列面試題總結

倆個棧實現一個佇列

原理圖

這裡寫圖片描述

注意一定要謹防pop時,容器內沒有元素而引發的錯誤。
class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        if (stack1.empty()) {
            cout << "佇列中無元素pop失敗" << endl;
            exit(1);
        }
        while (!stack1.empty())
        {
            stack2.push(stack1.top());
            stack1.pop();
        }
        int
ret = stack2.top(); stack2.pop();//這個pop挺重要的 ,必須pop這才符合 要不根本該元素一直是佇列的頭元素 while (!stack2.empty()) { stack1.push(stack2.top()); stack2.pop(); } return ret; } private: stack<int> stack1; stack<int> stack2; };

倆個佇列實現一個棧

class Solution2
{
public:
    void push(int node) {
        queue1.push(node);
    }

    int pop() {
        if (queue1.empty())
        {
            cout << "棧為空不能pop" << endl;
            exit(2);
        }
        while (queue1.size()>1)
        {
            queue2.push(queue1.front());
            queue1.pop();
        }
        int
ret = queue1.front(); queue1.pop(); while (!queue2.empty()) { queue1.push(queue2.front()); queue2.pop(); } } private: queue<int> queue1; queue<int> queue2; };

實現一個棧Stack,要求實現Push、Pop、Min的時間複雜度為O(1)

思路

第一種方法定義倆個棧,一個儲存元素一個儲存min值。每次入棧時要比較如果該元素小於等於min棧的棧頂元素時就把該元素也向min棧中入棧,否則只入儲存元素的棧。出棧時如果該元素等於min棧的棧頂元素則倆個棧都要執行pop操作,否則只出儲存元素棧的元素。
第二種方法只是用一個棧。每次入棧時,入倆個元素。先入要入的元素,再入min值。每次入的時候要判斷,如果棧不為空,取棧頂元素。如果該元素小於棧頂元素就該元素入倆次,即從該元素後,該棧的最小元素得到了更新,否則先入該元素,再入原先棧頂的元素。出站棧時倆個倆個出。

方法2class Mystack{
public:
    Mystack()
    {}
    void push(T data)
    {
        if (_s.empty())
        {
            _s.push(data);
            _s.push(data);
        }
        else{
            int min = _s.top();
            if (data < min)
            {
                _s.push(data);
                _s.push(data);
            }
            else{
                _s.push(data);
                _s.push(min);
            }
        }
    }
    void pop()
    {
        if (_s.empty()){
            cout << "棧為空不能pop" << endl;
            return;
        }
        _s.pop();
        _s.pop();
    }
    T min()
    {
        return _s.top();
    }
private:
    stack<T> _s;
};

元素出棧、入棧順序的合法性。

舉個栗子:入棧的序列(1,2,3,4,5),出棧序列為(4,5,3,2,1),則合法。入棧的序列(1,2,3,4,5),出棧序列為(4,5,2,3,1),則不合法。也就是給你入棧序列,和出棧序列,看它符不符合一個棧的規律。

思路

因為棧是先進後出。所以出棧序列和入棧序列應該是反向的一組序列。但是有個例外,就是有一個元素先進然後立即出再入下一個元素,這種情況入棧序列和出棧序列就不再是反序的了。這樣的情況影響出棧的序列。所以可以用出棧序列中的第一個元素在入棧序列中找到相應的下標。因為該元素是第一個出棧的元素,在此之前沒有元素出棧。故在此之前進棧的元素嚴格遵循先進後出。而在該元素後入棧的元素可以遵循,也可以不遵循以例外的方式出棧所以是任意順序的。
所以我們只判斷在此之前是嚴格反序的話就是合法,不是嚴格反序就是非法。但是我們得在這樣判斷前,確保倆個數組元素都是相同的,所以我使用了倆段空間儲存這倆個數組的值,然後快排看了下這倆個數組的值是否都完全相同。

int partion(int*arr,int left,int right)
{
    int begin = left;
    int end = right;
    int &key = arr[right];
    while (begin < end)
    {
        while (begin < end&&arr[begin] <= key) ++begin;
        while (begin < end&&arr[end] >= key) --end;
        if (begin < end)
        {
            arr[begin] ^= arr[end];
            arr[end] ^= arr[begin];
            arr[begin] ^= arr[end];
        }
    }
    if (begin != right) {
        arr[begin] ^= key;
        key ^= arr[begin];
        arr[begin] ^= key;
    }
    return begin;
}
void  quicksort(int*arr, int left ,int right)
{
    if (left<right)
    {
        int Base = partion(arr, left, right);
        quicksort(arr, left, Base - 1);
        quicksort(arr, Base+1, right);
    }

}
bool My_sort(int*test1, size_t len, int*test2, size_t len2)
{
    std::sort(test1, test1+len);//sort的end為尾隨位置,可以用sort或者自己寫個快排什麼的基本上sort的時
    std::sort(test2, test2 + len);//間複雜度是nlog2n
    //quicksort(test1,0,len-1);
    //quicksort(test2,0,len2-1);
    for (size_t idx = 0; idx < len; ++idx)
    {
        if (test1[idx] != test2[idx]) return false;
    }
    return true;
}
bool stack_legal(int arr[],int arr_2[],size_t len ,size_t len_2)//這個方法時間複雜度O(nlog2)
{                                                           // 空間複雜度O(n)
    assert(arr != NULL&&arr_2 != NULL);
    if (len != len_2) return false;
    if (len == 0 ||len_2==0) return true;
    if (len == 1&&len_2==1)
    {
        if (arr[0] == arr_2[0]) return true;
        else return false;
    }
    int *test_arr = new int[len];
    int *test_arr2 = new int[len_2];
    memmove(test_arr, arr, len*sizeof(int));
    memmove(test_arr2, arr_2, len_2*sizeof(int));
    if (!My_sort(test_arr, len, test_arr2, len_2)) return false;
    size_t pos = 0;
    while (arr[pos] != arr_2[0])++pos;
    size_t idx = 0;
    while (pos > 0)
    {
        if (arr[idx] != arr_2[len_2 - 1 - idx]) return false;
        idx++;
        --pos;
    }
    return true;;
}

判斷一棵樹是否是完全二叉樹

思路

我主要使用了層序遍歷的思想,檢測每一層的節點的合法性。
①當出現了只有左子樹節點沒有右子樹的節點,那麼我給一個標記置為True,以後遍歷的每個節點再有子節點的話就不是完全二叉樹。
②如果當該層節點只有右子樹沒有左子樹那麼該樹不是完全二叉樹。
所以根據上面倆條規則來解決這個問題

該圖就是我所描述的幾種情況

這裡寫圖片描述

程式碼

bool complete_tree(Node*Root)
{
    if (Root == NULL) return true;
    bool Last = false; //該標記表示是否發現只有一個左子節點的子樹
    queue<Node*> qcon;
    qcon.push(Root);
    Node*pCur = NULL;
    while (!qcon.empty())
    {
        pCur = qcon.front();
        if (Last&&(pCur->_PLeft!=NULL||pCur->_PRight!=NULL))
        {
            return false;
        }
        if (pCur->_PLeft !=NULL&&pCur->_PRight!=NULL)
        {
            qcon.push(pCur->_PLeft);
            qcon.push(pCur->_PRight);
        }
        if (pCur->_PLeft != NULL&&pCur->_PRight == NULL)
        {
                qcon.push(pCur->_PLeft);
                Last =true;
        }
        if (pCur->_PRight != NULL&&pCur->_PLeft == NULL)
        {
            return false;
        }
        qcon.pop();
    }
    return true;
}