题目如下:
Total Submit: 5453 Accepted Submit: 2313
How can anagrams result from sequences of stack operations? There are two sequences of stack operators which can convert TROT to TORT:
[ i i i i o o o o i o i i o o i o ]
where i stands for Push and o stands for Pop. Your program should, given pairs of words produce sequences of stack operations which convert the first word to the second.
Input
The input will consist of several lines of input. The first line of each pair of input lines is to be considered as a source word (which does not include the end-of-line character). The second line (again, not including the end-of-line character) of each pair is a target word. The end of input is marked by end of file.
Output
For each input pair, your program should produce a sorted list of valid sequences of i and o which produce the target word from the source word. Each list should be delimited by
[ ]
and the sequences should be printed in "dictionary order". Within each sequence, each i and o is followed by a single space and each sequence is terminated by a new line.
Process
A stack is a data storage and retrieval structure permitting two operations:
Pop - to retrieve the most recently pushed item
We will use the symbol i (in) for push and o (out) for pop operations for an initially empty stack of characters. Given an input word, some sequences of push and pop operations are valid in that every character of the word is both pushed and popped, and furthermore, no attempt is ever made to pop the empty stack. For example, if the word FOO is input, then the sequence:
i i o i o o | is valid, but |
i i o | is not (it's too short), neither is |
i i o o o i | (there's an illegal pop of an empty stack) |
Valid sequences yield rearrangements of the letters in an input word. For example, the input word FOO and the sequence i i o i o o produce the anagram OOF. So also would the sequence i i i o o o. You are to write a program to input pairs of words and output all the valid sequences of i and o which will produce the second member of each pair from the first.
Sample Input
madam adamm bahama bahama long short eric rice
Sample Output
[ i i i i o o o i o o i i i i o o o o i o i i o i o i o i o o i i o i o i o o i o ] [ i o i i i o o i i o o o i o i i i o o o i o i o i o i o i o i i i o o o i o i o i o i o i o i o ] [ ] [ i i o i o i o o ]
本题是跟堆栈操作相关的题目,要求通过堆栈的入栈出栈操作从输入串转换成输出串的所有操作序列。
在近期对堆栈这种数据结构的学习过程中,遇到过这样一道跟本题相关的题目。有一列火车车厢依次编号1,2,..n,一个火车道,火车道看作一个堆栈,给出火车车厢编号的输入序列以及输出序列,要求判断是否能够通过车厢进入火车道从输入序列得到输出序列。这个题目的解题思路是同时扫描输入序列和输出序列,进行出栈入栈操作,如最后输入序列和输出序列均扫描完毕并且堆栈为空,则可以从输入序列得到输出序列。具体解法如下:
假设输入序列S,输出序列T,堆栈为Stack。扫描到S[i]和T[j],0<=i<S.length,0<=j<T.length。
If(S[i]==T[j])
{
i++;
j++;
}
else
{
Stack.push(S[i]);
i++;
}
else if(Stack.top()==T[j])
{
Stack.pop();
j++;
}
若i == S.length && j == T.length && S.empty(),则可以从输入序列得到输出序列。
回到本题,解法可以借鉴上面这道题目。但是存在以下不同:(1)本题要求所有的操作序列;(2)输入中可以存在重复元素。根据第一个不同点,采用递归的方式搜索所有可行的操作序列,用栈来记录输入序列中出入的元素,用队列来记录产生的操作序列;第二个不同点决定S[i]==T[j]时,不能简单地入栈出栈就完事。具体处理方式如下:
S[i] == T[j]
(1) 将S[i]到S[sourceNext[i]-1]的元素入栈,i=sourceNext[i],递归处理(i,j)
程序中我们定义了一个数组sourceNext[0..S.length-1],其中sourceNext[i](0<i<S.length)表示最小的j(i<j),S[i]==S [j]。 若不存在这样的j,则sourceNext[i]=-1。
(2) S[i]入栈出栈,i=i+1,j=j+1,递归处理(i,j)
(3) If(S.top()==T[j])
{S.pop();j=j+1;递归处理(i,j)}
S[i] != T[j]
(1) S[i]入栈,i=i+1,递归处理(i,j)
(2) If(S.top()==T[j])
{S.pop();j=j+1;递归处理(i,j)}
处理S[i] == T[j]的(2) 存在一个问题,如sourceNext[i]=i+1,则(2)的处理产生的操作序列与下一层递归(i+1,j)(3)产生的操作序列重合。可以假设S[i]=a,S[i+1]=a,T[j]=a,画个示意图就会发现问题。因此,只有当SourceNext[i] != i +1时进行(2)。当i=S.length && j == T.length && S.empty()时,队列记录了一个完整的操作序列。此外,题目要求有序输出操作序列。直观方法时用一个表来记录所有的操作序列,然后排序输出。但是在问题规模很大时,这几乎不可能实现。因此,我们需要在处理过程中,就要保证当前产生的操作序列是有序的。回过头来看,假设当前生成的操作序列是有序的,当S[i] == T[j]时,(1)产生的是若干个i,(2)产生i o,(3)产生o,因此为保证加入操作符号后新产生的序列也是有序的,S[i] == T[j]时处理的先后顺序应该是(1)(2)(3)。S[i] != T[j]时同理。这样最终产生的完整的操作序列均是有序的。
解答的源代码如下:
#include <iostream>
#include <stack>
#include <deque>
#include <map>
#include <string>
using namespace std;
{
char c;
int next;
};
static int *sourceNext;
static string target;
static deque<char> Q;
#define POP 'o'
void f(int i, int j)
{
if(i < 0 || j < 0)
{
return;
}
if(source[i] == target[j])
{
if(source[i] != 0)
{
int next = sourceNext[i];
int k;
{
S.push(source[k]);
Q.push_back(PUSH);
}
for(k = i;k<next;k++)
{
S.pop();
Q.pop_back();
}
{
Q.push_back(PUSH);
Q.push_back(POP);
f(i+1,j+1);
Q.pop_back();
Q.pop_back();
}
{
char temp = S.top();
S.pop();
Q.push_back(POP);
f(i,j+1);
S.push(temp);
Q.pop_back();
}
else if(S.top() == 0)
{
//successful
int start = 0;
int oriStrPos = 1;
{
cout<<Q[k]<<" ";
}
if(Q.size()>0)
cout<<endl;
}
}
else
{
if(source[i] != 0)
{
S.push(source[i]);
Q.push_back(PUSH);
f(i+1,j);
S.pop();
Q.pop_back();
}
{
char temp = S.top();
S.pop();
Q.push_back(POP);
f(i,j+1);
S.push(temp);
Q.pop_back();
}
}
}
{
int sourceLen = source.length();
memset(L,0,MAXLETTERS);
if(sourceLen > 0)
sourceNext = new int[sourceLen];
for(int i = 0;i<sourceLen;i++)
{
char c = source[i];
if(L[c]!=-1)
sourceNext[L[c]] = i;
L[c] = i;
sourceNext[i] = -1;
}
}
{
while(cin>>source>>target)
{
while(!S.empty())
S.pop();
S.push(0);
ft();
cout<<"["<<endl;
f(0,0);
cout<<"]"<<endl;
if(sourceNext != NULL)
{
delete[] sourceNext;
sourceNext = NULL;
}
}
}
下面是修改后的代码:
#include <iostream>
#include <stack>
#include <deque>
#include <map>
#include <string>
using namespace std;
#include <string.h>
static string source;
static string target;
static stack<char> S;
static deque<char> Q;
static int l;
#define PUSH 'i'
#define POP 'o'
void f1(int i, int j)
{
if(i == l && j == l)
{
for(int k = 0;k<Q.size();k++)
{
cout<<Q[k]<<" ";
}
if(Q.size()>0)
cout<<endl;
return;
}
if(i < l)
{
S.push(source[i]);
Q.push_back(PUSH);
f1(i+1,j);
S.pop();
Q.pop_back();
}
if(j < l && !S.empty() && S.top()==target[j])
{
char temp = S.top();
S.pop();
Q.push_back(POP);
f1(i,j+1);
S.push(temp);
Q.pop_back();
}
}
int main(int argc,char **argv)
{
while(cin>>source>>target)
{
cout<<"["<<endl;
int sourceLen = source.length();
int targetLen = target.length();
if(sourceLen == targetLen)
{
l = sourceLen;
f1(0,0);
}
cout<<"]"<<endl;
}
return 0;
}