对于一个入栈序列输出所有的出栈序列

网上有很多解法,但个人感觉不够清晰。下面本人献丑来写下自己的解法。力求简明易懂。首先这是个卡特兰数,学过组合数学的同学都知道。没学过的可以看下下面这个例子。

有2n个人排成一队进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票可找零,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)。

对于这个例子,剧院要想总有零钱可找,那么目前进入剧院的人数中,揣着10元钞票的人数必须少于等于揣着5元钞票的,不然肯定在某个人那出现没零钱找的情况。

现在回到正题上来对于一个给定入栈序列,怎么求它的出栈序列呢?

我们可以把入栈记为1,出栈记为0.那么前缀子序列中1的个数必须大于等于0的个数,即入栈次数要大于等于出栈次数,如1 1 0 1 0 0,它的任意前缀序列中1的个数是大于等于0的个数的。

我们来看个例子:对于1 2 3这个入栈序列,1 1 0 1 0 0就是一个入栈出栈序列,第一个1代表元素1入栈,然后第二个1代表元素2入栈,然后第三个是0,代表出栈,即元素2出栈,然后第四个是1,代表元素3入栈,然后第五个是0,代表出栈,即元素3出栈,然后第六个是0,代表元素1出栈。最后1 1 0 1 0 0就代表了出栈序列2 3 1。

那么现在的问题就转换为如何求出所有符合条件的0 1序列了。其实这和以下问题相同:给定括号对数,输出所有符合要求的序列。如2对括号,输出有()()或者(())两种。1可以看成'(',0可以看成‘)’。

下面贴上本人的程序,并给出详细注释。

#include <iostream>
#include <vector>
using namespace std;


void func(vector<char>kind,int count[],int n)
{
    if(count[0]>=1)
    {
        kind.push_back('(');
        count[0]--;
        func(kind,count,n);
        count[0]++;
        kind.pop_back();
    }
    if((count[1]>=1) && (count[1]>count[0]))
    {
        kind.push_back(')');
        count[1]--;
        func(kind,count,n);
        count[1]++;
        kind.pop_back();
    }
    if(kind.size()==2*n)
    {
        vector<char>::iterator iter;
        for(iter=kind.begin();iter!=kind.end();iter++)
        {
            cout<<(*iter)<<" ";
        }
        cout<<endl;
    }
}


int main()
{
    int n;
    cout << "please input the number of ():" << endl;
    cin>>n;
    int count[2]={n-1,n};
    vector<char>kind;
    kind.push_back('(');
    func(kind,count,n);
    return 0;
}

count[0]存着左括号数目,count[1]存着右括号数目。一开始kind中压入左括号,因为第一个肯定是左括号。然后count数组初始化为n-1个左括号,n个右括号。然后我们递归的处理。如果剩余左括号数count[0]大于0,就可以把左括号压栈。而对于右括号,栈中左括号个数必须多于右括号个数,也就是剩余右括号个数大于左括号个数,即count[1]>count[0]时,才能将右括号压栈。如果栈中元素个数达到2n时,就把栈中元素输出。

下面贴出出栈序列代码,几乎和上面相同。

#include <iostream>
#include <stack>
#include <vector>
using namespace std;


int number=0;
void func(vector<int>kind,int count[],int n,int A[])
{
    if(count[0]>=1)
    {
        kind.push_back(1);
        count[0]--;
        func(kind,count,n,A);
        count[0]++;
        kind.pop_back();
    }
    if((count[1]>=1) && (count[1]>count[0]))
    {
        kind.push_back(0);
        count[1]--;
        func(kind,count,n,A);
        count[1]++;
        kind.pop_back();
    }
    if(kind.size()==2*n)
    {
        vector<int>::iterator iter;
        stack<int>stk;
        int j=0;
        for(iter=kind.begin();iter!=kind.end();iter++)
        {
            //cout<<(*iter)<<" ";
            if(1==(*iter))
            {
                stk.push(A[j]);
                j++;
            }
            else
            {
                cout<<stk.top()<<" ";
                stk.pop();
            }
        }
        number++;
        cout<<endl;
    }
}


int main()
{
    int n,i;
    cout << "please input the number:" << endl;
    cin>>n;
    int A[n];
    cout << "please input the push sequence:" << endl;
    for(i=0;i<n;i++)
    {
        cin>>A[i];
    }
    int count[2]={n-1,n};
    vector<int>kind;
    kind.push_back(1);

    cout<<"the result is:"<<endl;
    func(kind,count,n,A);
    cout<<"total:"<<number<<endl;
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用栈来实现,具体步骤如下: 1. 定义一个栈,用来存储入栈序列中的元素。 2. 遍历入栈序列,对于每一个元素,将其入栈。 3. 每次入栈后,检查栈顶元素是否与出栈序列的下一个元素相同,如果相同,则将栈顶元素出栈,并将出栈序列的指针向后移动一位。 4. 重复步骤3,直到栈为空或者栈顶元素与出栈序列的下一个元素不相同。 5. 如果遍历完入栈序列后,栈为空,则说明入栈序列可以按照出栈序列的顺序出栈;否则,说明无法按照出栈序列的顺序出栈。 下面是用C语言实现的代码: #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 typedef struct { int data[MAX_SIZE]; int top; } Stack; void init(Stack *s) { s->top = -1; } int is_empty(Stack *s) { return s->top == -1; } int is_full(Stack *s) { return s->top == MAX_SIZE - 1; } void push(Stack *s, int x) { if (is_full(s)) { printf("Stack is full\n"); exit(1); } s->data[++s->top] = x; } int pop(Stack *s) { if (is_empty(s)) { printf("Stack is empty\n"); exit(1); } return s->data[s->top--]; } int peek(Stack *s) { if (is_empty(s)) { printf("Stack is empty\n"); exit(1); } return s->data[s->top]; } void print_stack(Stack *s) { int i; for (i = s->top; i >= 0; i--) { printf("%d ", s->data[i]); } printf("\n"); } void check(Stack *s, int *out, int n) { int i = 0, j = 0; while (i < n) { if (!is_empty(s) && peek(s) == out[j]) { pop(s); j++; } else { push(s, i++); } } while (!is_empty(s) && peek(s) == out[j]) { pop(s); j++; } if (is_empty(s)) { printf("The input sequence can be converted to the output sequence\n"); } else { printf("The input sequence cannot be converted to the output sequence\n"); } } int main() { Stack s; int input[] = {1, 2, 3, 4, 5}; int output[] = {4, 5, 3, 2, 1}; int n = sizeof(input) / sizeof(int); init(&s); check(&s, output, n); return 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值