栈、队列面试题总结

俩个栈实现一个队列

原理图

这里写图片描述

注意一定要谨防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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值