常考编程题之栈和队列

6 篇文章 0 订阅
5 篇文章 0 订阅


使用两个栈实现队列

思路:元素进栈以后,只能优先弹出末尾元素,但是队列每次弹出的却是最先进入的元素,如果能够将栈中元素全部取出来,才能访问到最前面的元素,此时,可以用另一个栈来辅助取出。

class solution
{
public:
    //入队列就正常入栈
    void push(int node)
    {
        stack1.push(node);
    }
    int pop()
    {
        //将第一个栈中内容弹出放入第二个栈中
        while(!stack1.empty())
        {
            stack2.push(stack1.top());
            stack1.pop();
        }
        //第二个栈栈顶就是最先进来的元素,即队首
        int res = stack2.top();//获取栈顶元素
        stack2.pop();//移除栈顶
        //再将第二个栈的剩余元素放回第一个栈
        while(!stack2.empty())
        {
            stack1.push(stack2.top());
            stack2.pop();
        }
        return res;
    }
private:
    stack<int> stack1;//堆栈模板
    stack<int> stack2;
};

使用两个队列实现栈

思路:队列只能进行队首出,队尾进,先进先出,而栈先进后出
则将队列的前n-1个元素弹出放入第二个队列,剩余的最后一个元素弹出输出即可实现栈

class mystack
{
public:
    void push(int data)
    {
        q1.push(data);
    }
    int pop()
    {
        //将第一个队列前n-1个数据放入第二个队列
        if(q1.empty())
        {
            return 0;
        }else if(q1.size() == 1)
        {
            int res = q1.front();
            q1.pop();
            return res;
        }
        int s = q1.size();
        for(int i = 0; i<s-1;i++)
        {
            //将第一个队列的首元素放入第二个队列队尾
            q2.push(q1.front());
            q1.pop();
        }
        //第一个队列的最后一个元素输出
        int res = q1.front();
        //将第二个队列的元素放入第一个队列
        while(!q2.empty())
        {
            q1.push(q2.front());
            q2.pop();
        }
        return res;
    }
private:
    queue<int> q1;//队列模板
    queue<int> q2;
};

有效括弧序列

给出一个仅包含字符‘(’,‘)’,‘{’,‘}’,‘[’,']'的字符串,判断给出的字符串是否是合法的括号序列,括号必须以正确的顺序关闭,”()“和”(){}[]“都是合法的括号序列,但"(]“和”([)]"不合法
要求:空间复杂度O(n),时间复杂度O(n)

思路:
遍历字符串,遇到’(‘’{‘’[’ 系列的括号,将对应的’)‘’}‘’]'元素入栈,若遇到与栈顶元素(右括号系列)相同,则栈顶出栈,遍历完为空则为有效括弧。

//有效括弧序列
class bracket
{
public:
    bool isVaild(string s)
    {
        //借助栈来判断
        stack<char> temp;
        int len = s.length();
        //遍历字符串
        for(int i  = 0; i < len; i++)
        {
             //'['与']'之间相差2,'('与')'之间相差1,'{'与'}'之间相差2
            if(temp.empty()||(s[i]-1 != temp.top()&&s[i]-2 != temp.top()))
                temp.push(s[i]);
            else 
                temp.pop();
        }
        //为空是有效括弧,不为空为无效
        return temp.empty();
    }
};

求最小的k个数

给定一个长度为n的可能有重复值的数组,找出其中不去重的最小的k个数。
例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字为1,2,3,4
要求:空间复杂度O(n),时间复杂度O(nlogn)

思路:排序,截取

//求最小的k个数
class solution1
{
public:
    vector<int> get_top_k(vector<int> &va,int k)
    {
    	vector<int> res;
        if (k == 0 || k > input.size()) return res;
        priority_queue<int> pq;//优先队列
        for (int i = 0; i < input.size(); ++i) {
            if (pq.size() < k) pq.push(input[i]);
            else if (input[i] < pq.top()) {
                pq.pop();
                pq.push(input[i]);
            }
        }
        while (!pq.empty()) {
            res.push_back(pq.top());
            pq.pop();
        }
        return res;
    }
};

求数据流的中位数

//求数据流中的中位数
class solution2
{
public:
    public:
    void Insert(int num) {
        // 时间复杂度O(logN),空间复杂度O(N)
        if (maxHeap.empty() || num < maxHeap.top()) maxHeap.push(num);
        else minHeap.push(num);
        if (maxHeap.size() > minHeap.size() + 1) {
            minHeap.push(maxHeap.top());
            maxHeap.pop();
        } else if (minHeap.size() > maxHeap.size() + 1) {
            maxHeap.push(minHeap.top());
            minHeap.pop();
        }
    }

    double GetMedian() { 
    // 时间复杂度O(1),空间复杂度O(1)
        if (maxHeap.size() > minHeap.size()) return maxHeap.top();
        else if (maxHeap.size() < minHeap.size()) return minHeap.top();
        else return (maxHeap.top() + minHeap.top()) / 2.0;
    }
private:
    priority_queue<int, vector<int>, less<int>> maxHeap;
    priority_queue<int, vector<int>, greater<int>> minHeap;
};

表达式求值

思路:
一.处理运算符优先级的问题。
把减号看成加一个数的相反数,则表达式只有乘除加,乘除的优先级高,则可把加减前后的数放入栈中,遇到乘除把前后俩个数乘除后的结果入栈,最后把存的数字全部相加即可。
二.处理括号问题
可把括号中的部分看成一个新的表达式,可将新的表达式递归求解,得到一个数字,再运算.

具体步骤:
1.使用栈辅助处理优先级,默认符号位加号。
2.遍历字符串,遇到数字,则将连续的数字字符部分转化为int型数字。
3.遇到左括号,则将括号后的部分送入递归,处理子问题,遇到右括号代表已经达到这个子问题的结尾,结束继续遍历字符串,将子问题的加法部分相加为一个数字返回。
4.当遇到符号的时候如果是+,得到的数字正常入栈,如果是-,将其相反数入栈,如果是*/,则将栈中内容弹出与后一个元素相乘/除再入栈。
5.最后将栈中剩余的所有元素,进行一次全部相加。

//表达式求值
class solution3
{
public :
    vector<int> function(string s, int index)
    {
        //定义辅助栈
        stack<int> stack;
        int num = 0;
        //默认运算符为+
        char op = '+';
        int i;
        for(i = index; i < s.length();i++)
        {
            //数字转化为int数字
            if(isdigit(s[i]))
            {
                num = num * 10 +s[i]-'0';
                if(i!=s.length()-1)
                {
                    continue;
                }
            }
            //碰到'('时,把整个括号内的当成一个数字处理
            if(s[i] == '(')
            {
                //递归处理括号
                vector<int> res = function(s,i+1);
                num = res[0];
                i = res[1];
                if(i!=s.length()-1)
                    continue;
            }
            int temp = 0;
            switch(op)
            {
            //加减号先入栈
            case '+':
                stack.push(num);
                break;
            case '-':
                //相反数
                stack.push(-num);
                break;
            case '*':
                temp = stack.top();
                stack.pop();
                stack.push(temp*num);
                break;
            case '/':
                temp = stack.top();
                stack.pop();
                stack.push(temp/num);
                break;
            }
            num = 0;
            //右括号结束递归
            if(s[i] == ')')
            {
                break;
            }
            else
            {
                op = s[i];
            }
        }
        int sum = 0;
        //栈中元素相加
        while(!stack.empty())
        {
            sum+=stack.top();
            stack.pop();
        }
        //将sum和i返回
        vector<int> a;
        a.push_back(sum);
        a.push_back(i);
        return a;
    }
    int solve(string s)
    {
        return function(s,0)[0];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值