9.21算法(栈)

用两个栈实现队列

栈:只允许在一头进行入队和出队,先进后出

队列:只允许一头入队,另一头出队,先进先出

如果先都放入一个栈中,就是倒序的,然后再把第一个栈中的元素依次移动到另一个栈中,又倒了一次序,就是正序了,即先进先出

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }//先都放入一个栈中

    int pop() {
        int res;
        while(!stack1.empty()){
            stack2.push(stack1.top());//把第一个栈中的元素倒到第二个栈中
            stack1.pop();
        }
        res=stack2.top();//此时第二个栈的第一个元素就是最先入队的元素
        stack2.pop();
        while(!stack2.empty()){
            stack1.push(stack2.top());//再把第二个栈的元素都倒到第一个中,目的是为了下一步的入队,即从尾部放入元素
            stack2.pop();
        }
        return res;
    }

private:
    stack stack1;
    stack stack2;
};

包含min函数的栈

有一个误区是,只用一个值存储当前栈的最小值,但如果这个最小值出栈后,就没了

所以函数就是要,根据栈的状态,时刻更新最小值

那就是说当前栈有几个元素,就应该用几个元素保存最小值,表示分别在栈有几个元素时所存储的最小值

所以用两个栈,一个栈就是存值的,另一个就是当前栈的最小值,那么操作就是每入栈一个元素,就和上个Min栈中的栈顶元素(表示前面所有元素的Min)比较,如果比它小,就让当前的栈的min为这个新入的元素,如果不是,那就依旧保留之前的min,直到遇到一个比它小的才更新。

stackcommon;
stackminnum;
void push(int val) {
	common.push(val);
	if (minnum.empty() || minnum.top() > val) {
		minnum.push(val);
	}
	else {
		minnum.push(minnum.top());
	}
}
void pop() {
	common.pop();
	minnum.pop();
}
int top() {
	return common.top();
}
int min() {
	return minnum.top();
}

有效括号序列 

遇到左括号序列就入栈,遇到右括号序列就出栈

最后如果栈有余或者遇到右括号但是栈为空,就是false

怎么保证遇到的右括号是和当前左括号栈的栈顶元素匹配?

不应该让左括号系列入栈,而是应该让接下来期望遇到的元素入栈,如果还是左括号序列,就接着入栈期望元素,如果遇到了不是左括号序列的元素,那么正确的必须是栈顶元素的期望的元素,不然就是错误的。

stacks1;
for (int i = 0; i < s.length(); i++) {
	if (s[i] == '(') {
		s1.push(')');
	}
	else if (s[i] == '[') {
		s1.push(']');
	}
	else if (s[i] == '{') {
		s1.push('}');
	}
	if (s1.empty()) {
		return false;
	}
	else if (s1.top() == s[i]) {
		s1.pop();
	}
}
return s1.empty();

火车入栈问题

题意为根据入栈顺序判断能否给出指定的出栈顺序

用三个栈,一个栈为入栈顺序,一个栈为出栈顺序,一个辅助栈来模拟

根据入栈顺序,依次入栈,每入栈一个元素,就判断一下和当前出栈顺序的栈顶元素是否相同,如果不相同,接着按照入栈顺序往辅助栈里入元素,直到当前元素和出栈顺序的栈顶元素相同,就开始尝试出栈,直到当前元素和出栈顺序的栈顶元素不同,再接着入栈

可以有剪枝,就是如果原入栈是单调的,那么

最后如果入栈栈空了,辅助栈的栈顶元素和出栈栈的栈顶元素不同,那就是false

关于指定栈元素数量的出栈可能情况有多少种

思路1:根据第一个元素的出栈顺序,完成一次情况的划分

分析:1) 如果元素a在1号位置,那么只可能a进栈,马上出栈,此时还剩元素b、c、d等待操作,就是子问题f (3); 2) 如果元素a在2号位置,那么一定有一个元素比a先出栈,即有f (1)种可能顺序(只能是b),还剩c、d,即f (2), 根据乘法原理,一共的顺序个数为f (1) * f (2); 3) 如果元素a在3号位置,那么一定有两个元素比1先出栈,即有f (2)种可能顺序(只能是b、c),还剩d,即f (1), 根据乘法原理,一共的顺序个数为f (2) * f (1); 4) 如果元素a在4号位置,那么一定是a先进栈,最后出栈,那么元素b、c、d的出栈顺序即是此小问题的解,即 f (3); 结合所有情况,即f (4) = f (3) + f (2) * f (1) + f (1) * f (2) + f (3); 为了规整化,我们定义f (0) = 1;于是f (4)可以重新写为: f (4) = f (0)*f (3) + f (1)*f (2) + f (2) * f (1) + f (3)*f (0) 然后我们推广到n,推广思路和n=4时完全一样,于是我们可以得到: f (n) = f (0)*f (n-1) + f (1)*f (n-2) +... + f (n-1)*f (0)

第一个元素在几号位置,就说明在入栈栈紧邻的后面几个元素入了栈,由它确定一个栈区间(这个区间里除了第一个元素之外怎么出的不管,但是要保证第一个元素是这个区间最后一个出的),然后出栈消除掉。之后就是下一个剩余规模的的第一个元素出栈位置问题。

思路2:根据最后出栈的元素,完成一次情况的划分

1……k……n,第k个元素最后出栈的可能情况

k最后出栈,表明k入栈时,栈里没有元素,即k-1前的元素都已完成,和k之后的没关系,独立过程。同时表明,k出栈时,k后的元素都已完成出栈,即以k为端点确定了两个栈区间。

k之前怎么出的我不管,k之后怎么出的也不管,但是要保证没有出k,即k入栈后就一直没动过,直到都动完了最后再出k

前者是说k-1的规模,后者是说n-k(不包含k,即k+1到n,共有n-k-1+1个数)的规模,(相加即n-1,少的1就是k)

9.21算法(栈)_第1张图片

9.21算法(栈)_第2张图片 

Catalan数 

你可能感兴趣的:(java,开发语言,c++)