144 阅读4分钟

两个栈实现队列

JZ9 用两个栈实现队列

入队:直接push进stack1

出队:如果stack2中有元素,直接pop;如果stack2中无元素,将stack1中元素依次pop然后push进stack2

我的代码:

void push(int node) 
{
    tack1.push(node);
}

int pop() {
    int tmp;
    int ans;
    //stack2 is not empty
    f(!stack2.empty())
    {
         ans = stack2.top();
         stack2.pop();
         return ans;
     }
     //stack2 is empty
     while(!stack1.empty())//ture  =1
     {
         tmp = stack1.top();
         stack1.pop();
         stack2.push(tmp);
     }
     ans = stack2.top();
     stack2.pop();
     return ans;
}

仔细观察后发现,stack2 is not empty时的代码与将stack1元素push进stack2后的代码相同。此外,STL容器中top()函数可以返回值,不需要定义tmp中间变量进行转存,而pop()函数只在容器中删除,无法得到删除的值,故可删去tmp中间变量。对代码进行精简后:

void push(int node)
{
    stack1.push(node);
}
int pop()
{
   if(stack2.empty())
   {
        while(!stack1.empty())
        {
            stack2.push(stack1.top());
            stack1.pop();
        }
    }
    int ans = stack2.top();
    stack2.pop();
    return ans;
}

两个队列实现栈

225. 用队列实现栈

class MyStack {
public:
    queue<int> q1,q2;
    MyStack() {

    }
    
    void push(int x) {
        //将q1中所有元素移至q2
        while(!q1.empty())
        {
            q2.push(q1.front());
            q1.pop();
        }
        q1.push(x);
        while(!q2.empty())
        {
            q1.push(q2.front());
            q2.pop();
        }

    }
    
    int pop() {
        int res = q1.front();
        q1.pop();
        return res;
    }
    
    int top() {
        return q1.front();
    }
    
    bool empty() {
        return q1.empty()&&q2.empty();
    }
};

key point

将最后进入的元素放置队首,然后将比起先进入“栈”的元素再放到队尾。

包含min函数的栈

JZ30 包含min函数的栈

所用的全局变量,如果未给出,可在public中自行定义。

get一个空间换时间的例子。

思路: 借助辅助栈min_val,此栈中一直存放着数值最小的元素。当要入栈的元素是最小元素时,同时push进两个栈,当要入栈的元素不是最小元素时,将min_val中的栈顶元素再入栈一次,以保证两个栈的元素个数相同,避免出现min_val栈为空的情况。【我自己想到了用辅助栈,但是只想在辅助栈中存一个元素(即,不断判断元素大小,只在辅助栈中保留一个元素),但是会出现辅助栈空的情况。只能说思路对了一半】

public:
    stack<int> normal;
    stack<int> min_val;
    void push(int value) {
        if(min_val.empty() && normal.empty())
        {
            min_val.push(value);
        }
        else
        {
            if(min_val.top() > value) min_val.push(value);
            else min_val.push(min_val.top());
        }
        normal.push(value);
    }
    void pop() {
        normal.pop();
        min_val.pop();
    }
    int top() {
        return normal.top();
    }
    int min() {
        return min_val.top();
    }

栈的压入、弹出序列对比

JZ31 栈的压入、弹出序列

思路: 【模拟元素入栈出栈】两个指针i,j分别指向压栈序列和出栈序列,i的内容不等于j的内容,则将i的内容入栈,i++;i的内容等于j的内容,则j++,i++;判断栈顶元素和j内容的关系,然后进行操作;最后栈空则对比正确。

case:

  1. pushV[i] == popV[j],相当于元素pushV[i]入栈之后又出栈,这时又分为两种情况
  • i == j,此时模拟的是元素入栈之后马上出栈的情况,继续比对下一对元素即可,无需对辅助栈进行操作
  • i > j,此时模拟的是一组元素pushV[0],pushV[1],...,pushV[i-1],pushV[i]入栈之后,pushV[i]出栈的情况。pushV[i]出栈后,又有两种可能:pushV[i+1]入栈,或者pushV[i-1]出栈。若是前者,需要比对的是pushV[i+1]popV[j+1]的关系。而后者则需要从辅助栈弹出栈顶元素与popV[j]对比。
  1. pushV[i] != popV[j],相当于元素入栈之后没有出栈,所以需要栈暂存pushV[i]
bool IsPopOrder(vector<int> pushV,vector<int> popV)
{
    stack<int> st;
    for(int i = 0, j = 0; i < pushV.size(); )
    {
        if(pushV[i] == popV[j])
        {
            i++;
            j++;
            while(!st.empty() && st.top() == popV[j]
            {
                st.pop();
                j++;
            }
        }
        else st.push(pushV[i++]);
    }
    return st.empty();
}

括号匹配

20. 有效的括号

我的思路: 遍历字符串,碰到左括号({[就将其压入栈中,碰到右括号,若此时栈中无左括号,则报错,若栈不为空,则将栈顶元素与该右括号进行匹配,成功则弹栈,否则报错。 关于代码简化:字符串长度为0或者奇数时,前者一定匹配,后者一定不匹配。

bool isValid(string s) 
{
    int len = s.length();
    //奇数
    if(len % 2 == 1) return false;
    //空字符串
    if(len == 0) return true;
    //非空偶数长字符串
    stack<char> st;
    for(int i = 0; i < len; i++)
    {
        //左括号直接入栈
        if(s[i] == '(' || s[i] == '['  || s[i] == '{'  )  st.push(s[i]);
        else //右括号
        {
            //stack is not empty
            if(!st.empty())
            {
                if(s[i] == ')' )
                {
                    if(st.top() == '(') st.pop();
                    else return false;
                }
                if(s[i] == ']' )
                {
                    if(st.top() == '[') st.pop();
                    else return false;
                }
                if(s[i] == '}' )
                {
                    if(st.top() == '{') st.pop();
                    else return false;
                }
            }
            //栈中无左括号,但是来了一个右括号
            else if(st.empty()) return false; 
        }    
    }
    return st.empty();
}

其他思路:

  1. 使用函数进行括号匹配
  1. 使用键值对map
map<char, char> mp = {
    {')','('},
    {']','['},
    {'}','{'}
};

for(char ch : s)
{
    if(mp.count(ch))
    {
        if(st.empty() || st.top() != mp[ch]) return false;
        else st.pop();
    }
    else st.push(ch);
}
return st.empty();

key-point

  • map使用,map<key,value>map[key] = value 以及map变量的赋值方式。

  • for(char ch:s)等价于for(int i = 0; i < s.length(); i++)

  1. 换一种入栈方式:入栈右括号 只需比较符号是否相等即可
for(int i = 0; i < len; i++)
{
    if(s[i] == '(') st.push(')');
    else if(s[i] == '[') st.push(']');
    else if(s[i] == '{') st.push('}');

    else if(st.empty()|| st.top() != s[i]) return false;
    else st.pop();
}
return st.empty();

注意:条件不能换为else if(st.top() != s[i] || st.empty()),会产生越界。原因在于C++中||的使用,A || B 其含义为A或B中任意一个成立则条件成立,但在其实现中,条件A对条件B有“屏蔽作用”,当条件A成立时,不再测试条件B。若将写成上述形式,则可能在栈空时取栈顶元素,所以越界。如,输入}{会在栈空时执行top操作。