题目:
给出两个字符串s1和s2,如果s1能够通过栈的模拟得到s2,则输出详细的步骤,并且输出所有的可性操作。这里用'i'表示Push(进栈,插入一个元素),用'o'表示Pop(退栈,删除一个元素)。比如s1="TROT", s2="TORT",则可以有以下两种操作:i i i i o o o o和i o i i o o i o。
先部署好一切:
stack为模拟的栈,A为处理到的原始串的下标,B为目标串的下标,0表示当前处理第1个进出操作,seq记录进出的信息,也即最后要打印的io序列。
处理结束条件:
进出进出,n是字符串长度,有进必有出,所以当k==2n的时候,也就得到我们的进出序列。这时不再调用函数里,直接return。
题目要求的是字典序排列,也即又能进又能出的时候,先进,因为i比o靠前。进:
出:
这里可以看到为什么上面进的时候要top--和A--,这个是还原操作。
答案是,在当前步,我们还可能进行出操作。所以要还原现场。考虑进的时候,我们让top++和A++了,表明栈多了一个字符,同时处理完了原始串A位置上的字符。但当前步还可能是出操作,所以要复原刚进来dfs时的各变量的值,也即让栈弹出一个字符,即top--。认为还没处理完原始串A位置上的字符,也即进行A--。
总的代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
int cmp(const void *_a,const void *_b){
int *a=(int *)_a;
int *b=(int *)_b;
return *a-*b;
}
char s1[100],s2[100];
int n;
//stack表示一个栈,top表示当前栈顶,A表示原先的字符串当前考虑的字符下标
//B表示目标字符串当前考虑的字符下标
//seq,表示操作序列
void dfs(char* stack,int top,int A,int B,int k,char* seq){
if(k==2*n){
if(A==n && B==n){
for(int i=0;i<k;i++){
printf("%c ",seq[i]);
}
printf("\n");
}
return;
}
if(A<n){
seq[k]='i';
++top;
stack[top]=s1[A];
A++;
dfs(stack,top,A,B,k+1,seq);
top--;
A--;
}
//栈非空且当前栈弹出的字符,等于目标串头字符时
if(top!=0 && stack[top]==s2[B]){
seq[k]='o';
char topCh=stack[top];
top--;
B++;
dfs(stack,top,A,B,k+1,seq);
stack[++top]=topCh;
B--;
}
}
void deal(){
char stack[210];
while(scanf("%s%s",s1,s2)==2){
int top=0;
printf("[\n");
n=strlen(s2);
int A=0,B=0;
char seq[210];
dfs(stack,top,A,B,0,seq);
printf("]\n");
}
}
int main(){
freopen("in.txt","r",stdin);
deal();
return 0;
}
来,试试 这题(比上面的题要容易,但原理一样)。