栈、队列面试题总结

来源:互联网 发布:考勤数据怎么导入u盘 编辑:程序博客网 时间:2024/05/22 08:00

俩个栈实现一个队列

原理图

这里写图片描述

注意一定要谨防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;}