c程序括号匹配检查buaa_c程序括号匹配检查

c程序括号匹配检查buaa_c程序括号匹配检查面试题之括号匹配分析( 出栈序列是否合法,给定一个入栈序列,求所有可能的出栈序列等等)题目:括号匹配分析给定字符串,输出括号是否匹配,例如,”()” yes;”)(” no;”(abcd(e)” no;”(a)(b)” ye

面试题之括号匹配分析( 出栈序列是否合法,给定一个入栈序列,求所有可能的出栈序列等等)   题目:括号匹配分析   给定字符串,输出括号是否匹配,例如,   ”()” yes;   ”)(” no;   ”(abcd(e)” no;   ”(a)(b)” yes。   要求必须用递归写,整个实现不可以出现一个循环语句。 分析   这个题目很多同学都见过了,如果没有后面的条件,会张口就说就来用栈来实现,时间复杂度O(n),空间复杂度O(n)。这个是很好的一个解答,没有 问题的。但是我们在做面试题,准备面试的过程中,每一个题目都不应该仅仅局限于某一个方法。应该尝试更多的思路,尽管有些思路的时间、空间复杂度并不是很 好,但是可以带来变化,举一反三,这才是真正的收获。   这个题要求了,只目能使用递归并且不能出现循环语句。这个时候,我们应该如何处理呢?其实告诉了大家递归,就比较好想了:怎么定义好问题和子问题。   如果字符串中的括号是匹配的,则'(‘的数量和’)’的数量是相等的,反之是不相等的。这样,在递归的过程中,可以保存一个变量,用来记录'(‘的 数量和’)’的数量是否匹配。这样定义递归问题f(p,count),表示当前字符p之前的字符串中'(‘的数量和’)’的数量的匹配情况,p表示指向当 前字符的指针。初始的时候,f(p, 0),递归的过程如下:       如果p为空,则考察count是否为0,如果为0,则匹配;如果不为0,则不匹配;   如果不为空,则考察当前字符p,如果p='(‘,则递归调用f(p++, count++);如果p=’)’,则递归调用f(p++, count–)。如果p是其他的字符,并不是'(‘和’)’,则递归调用f(p++, count),count不变,继续考虑下一次字符。其中需要检查和保证count>=0.       其实,递归的问题有的时候不是那么好像的,需要大家不断的练习。如果不采用count来记录括号匹配的情况,这个题目的递归也不好想。   基于栈的代码:   bool isMatched(const char *str) { stack<char> s; while(*str) { if(*str=='(‘) { s.push(‘(‘); } else if(*str==’)’) { if(!s.empty())//这里很重要,保证了如果输入)(,就直接退出 { s.pop(); } else { return false; } } str++; } return s.empty(); }   递归的代码:下面是我刚开始写的,有什么错误吗?   bool isMatchedRec(char *p,int count) { if(*p==’0′) { return count==0;//如果p为空,则考察count是否为0,如果为0,则匹配;如果不为0,则不匹配; } else { if(*p=='(‘) { //return isMatchedRec(p++,count++); 错误,在递归内要写前缀++,不要写后缀,否则无穷递归。 return isMatchedRec(++p,++count); } else if(*p==’)’) { return isMatchedRec(++p,–count); } else { return isMatchedRec(++p,count); } } }   错误在哪里;   假设我们输入“)(”,返回的还是true。   原因是没有没有检查count>=0.   正确的代码:   bool isMatchedRec(char *p,int count) { if(*p==’0′) { return count==0;//如果p为空,则考察count是否为0,如果为0,则匹配;如果不为0,则不匹配; } else { if(count>=0) { if(*p=='(‘) { return isMatchedRec(++p,++count); } else if(*p==’)’) { return isMatchedRec(++p,–count); } else { return isMatchedRec(++p,count); } } else return false; } }   可以把上面代码再简化下:   bool isMatchedRec2(const char* s,int count) { if(count<0) return false; if(*s==’0′) { return count==0; } else { if(*s=='(‘) count++; else if(*s==’)’) count–; } return isMatchedRec2(++s,count); }       参考:http://blog.csdn.net/buaa_shang/article/details/11726619   扩展问题;   假设字符串中包含{,[,( 三种括号,请判断是否匹配。   http://blog.chinaunix.net/uid-28458801-id-3664897.html       bool isPair(char a,char b) { bool flag=true; if(a=='{‘ && b==’}’) flag=true; else if(a=='[‘ && b==’]’) flag=true; else if(a=='(‘ && b==’)’) flag=true; else flag=false; return flag; } bool isMatched(const char *str) { stack<char> s; while(*str) { if(*str=='{‘ || *str=='[‘ || *str=='(‘ ) { /*if( (s.top()=='{‘) || (s.top()=='[‘&&*str!='{‘) && (s.top()=='(‘&& *str=='(‘) ) s.push(*str); else return false; */ s.push(*str); } else if(*str==’}’ || *str==’]’ || *str==’)’ ) { if(!s.empty())//这里很重要,保证了如果输入)(,就直接退出 { if(isPair(s.top(),*str)) { s.pop(); } else { return false; } } else { return false; } } str++; } return s.empty(); }       题目扩展           给你一个字符串,里面只包含”(“,”)”,”[“,”]”,”{“,”}”几种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。           例如:           []是匹配的,所需括号个数为 0;([])[]是匹配的, 所需括号个数为 0;((]是不匹配的, 所需最少括号个数为 3;([)]是不匹配的,所需最少括号个数为 2.               这道变种题大多数人的解题思路都是动态规划,思路如下。不知道大家有没有好的别的方法,求教。        1)用 dp[i][j] 表示从位置 i  到字符位置 j 所需的最少括号数。假定字符串是 “[ ( )”, 那么 dp[0][0] = dp[1][1]  = dp[2][2] = 1。               2)如果我们要算dp[i][j+1], 那么,最坏的情况是使得没有被匹配的括号数增加了,即 dp[i][j+1] 最多为 min( dp[i][j] + 1, dp[i+1][j+1] + 1). 但是,这可能不是我们想要的答案,因为在刚才的例子里,即:假定字符串是 “[ ( )”, 那么 dp[0][1] = dp[0][0] + 1= 2, 但是 dp[1][2] 却不等于 dp[1][1] + 1.              3)那么,什么情况下dp[i][j+1] = dp[i][j] + 1?只有当 字符串里从i 到 j 没有任何字符与第 j + 1 个字符匹配的时候。但是,如果存在和第 j + 1 个字符匹配的情况,问题就不一样了。           4)假设在i 到 j 之间存在一个字符(比如在位置 k)与第 j + 1 个字符匹配,那么我们相当于把原来的字符串分成了两个部分dp[i][k-1] 和 dp[k+1][j], 因为第k 个 和 j + 1 个字符已经匹配掉了。而且,我们不会再考虑 i 到 k – 1 的字符会和 k + 1 到 j 之间的字符匹配的情况,因为我们已经把这两个部分完全分开了。话句话说 dp[i][j+1] = min(min( dp[i][j] + 1, dp[i+1][j+1] + 1),  dp[i][k-1] + dp[k+1][j]).   #include<iostream> #include<string> #include<memory.h> using namespace std; bool is(char a, char b){ if(a == ‘(‘ && b == ‘)’) return 1; if(a == ‘[‘ && b == ‘]’) return 1; if(a == ‘{‘ && b == ‘}’) return 1; return 0; } int main(){ //dp[i][j] 表示从第i位至第j位的最小匹配长度 int t, i, j, k, dp[105][105]; cin >> t; while(t–){ string s; cin >> s; memset(dp, 0, sizeof(dp)); for(i = 0; i <= s.length(); ++i){ dp[i][i] = 1; } for(i = 2; i <= s.length(); ++i){ for(j = i – 1; j >= 1; –j){ dp[j][i] = dp[j][i – 1] + 1; for(k = j; k < i; ++k){ if(is(s[k – 1], s[i – 1])){ dp[j][i] = min(dp[j][i], dp[j][k – 1] + dp[k + 1][i – 1]); } } } } cout << dp[1][s.length()] << endl; } return 0; }    改写的更容易看懂 的代码:   dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j])k [i,j)   bool isPair(char a,char b) { if(a == ‘(‘ && b == ‘)’) return 1; if(a == ‘[‘ && b == ‘]’) return 1; if(a == ‘{‘ && b == ‘}’) return 1; return 0; } int match(int dp[100][100],char s[]) { for(int i=0;i<100;i++) for(int j=0;j<100;j++) dp[i][j]=0; int len=strlen(s); for(int i=0;i<=len;i++) dp[i][i]=1; for(int j=2;j<=len;j++) { for(int i=j-1;i>=1;i–) //i从1开始,说明dp[0]不存 { dp[i][j]=dp[i][j-1]+1; for(int k=i;k<j;k++) { if(isPair(s[k-1],s[j-1])) { dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j-1]); } } } } return dp[1][len]; }    递归版:   //递归版 #include<stdio.h> #include<string.h> const int inf = 0x0fffffff; #define min(x, y)(x < y ? x : y) #define low(x, y)((x == ‘(‘ && y == ‘)’) || (x == ‘[‘ && y == ‘]’)) char str[110]; int dp[110][110]; int fun(int x,int y) { if(dp[x][y] != -1) return dp[x][y]; if(x > y)return 0; if(x == y)return 1; int ans = inf; if(low(str[x], str[y])) ans = min(ans, fun(x + 1, y – 1)); for(int i = x;i < y; ++ i) ans = min(ans, fun(x, i) + fun(i + 1, y)); dp[x][y] = ans; return ans; } int main() { int T; scanf(“%d”, &T); while(T –) { scanf(“%s”, str); int len = strlen(str); memset(dp, -1, sizeof(dp)); printf(“%d   ”, fun(0, len – 1)); } }   参考:http://blog.acmj1991.com/?p=1142   http://www.dewen.org/q/8653/%E4%B8%80%E4%B8%AA%E6%8B%AC%E5%8F%B7%E5%8C%B9%E9%85%8D%E7%9A%84%E6%89%A9%E5%B1%95%E9%97%AE%E9%A2%98   另一题:   输入括号的数目,输出括号的各种合法匹配样式   输入 2   输出     (())   ()()   据说这是一道某公司的面试题,我们先来分析一下。括号匹配有合法有的不合法 如 (()))( 这样就不是合法的匹配样式。为了避免这种情况的出现,记录当前左括号的个数和右括号的个数,使右括号的个数不大于左括号的个数。主要思想类似于0-1背包问题,当进行到某一步的时候 有两种方法:放’(’ 和 放 ‘)’   void matching(int left,int right,int sum,vector<char> bracket) { if (left==sum&&right==sum) //如果左边和右边都为要匹配的个数,则输出结果 { vector<char>::iterator iter=bracket.begin(); for ( ;iter!=bracket.end();iter++) { cout<<*iter<<‘ ‘; } cout<<endl; return ; } if (left<=sum) { bracket.push_back(‘(‘); //放入左括号,然后递归 matching(left+1,right,sum,bracket); bracket.pop_back(); //递归后弹出左括号 } if (left>right&&left<=sum) { bracket.push_back(‘)’); matching(left,right+1,sum,bracket); bracket.pop_back(); } } int main(int argc, char* argv[]) { vector<char> bracket; //记录当前的匹配样式 int num; cin>>num; //输入括号的个数 matching(0,0,num,bracket); return 0; }   我最开始想的是回溯法,应该和八皇后问题思路一致。但这个程序不是。上面递归程序不好理解。   可以举个例子:sum=3时,   
c程序括号匹配检查buaa_c程序括号匹配检查   最开始一值是运行第二个递归:   (((,   接着:   放入一个),接着递归,又放入一个),又放入); 最后变成了:   ((()));    输出这个之后。    给定一个入栈序列,求所有可能的出栈序列   有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;   }   参考:http://blog.csdn.net/zz198808/article/details/7585385   一篇文章:   #include<iostream> #include<stack> using namespace std; static int counter; void outprint(stack<int> q){ while (q.size() != 0) { cout << q.top() << “-> “; q.pop(); } cout << endl; counter++; return; } //q 存放入栈序列 //stk 用于模拟入栈过程 //output 用于存放可能的出栈序列 void allPopSeq(stack<int> q,stack<int> stk,stack<int> output){ if((q.size() == 0)&&(stk.size()==0)&&(output.size() == 5)) { outprint(output); return; } if(q.size()!=0){//入栈 int v = q.top(); stk.push(v); q.pop(); allPopSeq(q,stk,output); stk.pop(); q.push(v);//回溯恢复 } if(stk.size()!=0) //出栈 { int v = stk.top(); stk.pop(); output.push(v); allPopSeq(q,stk,output); output.pop(); stk.push(v);//回溯恢复 } return; } int main() { int arr[5] = { 1, 2, 3, 4, 5 }; stack<int> stkValues; stack<int> stkOutput; stack<int> tmp; int i; for (i = 0; i != 5; ++i){ stkValues.push(arr[i]); } allPopSeq(stkValues, tmp, stkOutput); cout << counter << endl; }   http://www.cnblogs.com/fxplove/articles/2500898.html   程序员面试题100题(24)-栈的push、pop序列[数据结构]     题目:输入两个整数序列。其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。   比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。   分析:这到题除了考查对栈这一基本数据结构的理解,还能考查我们的分析能力。   这道题的一个很直观的想法就是建立一个辅助栈,每次push的时候就把一个整数push进入这个辅助栈,同样需要pop的时候就把该栈的栈顶整数pop出来。   我们以前面的序列4、5、3、2、1为例。第一个希望被pop出来的数字是4,因此4需要先push到栈里面。由于push的顺序已经由push序列确定了,也就是在把4 push进栈之前,数字1,2,3都需要push到栈里面。此时栈里的包含4个数字,分别是1,2,3,4,其中4位于栈顶。把4 pop出栈后,剩下三个数字1,2,3。接下来希望被pop的是5,由于仍然不是栈顶数字,我们接着在push序列中4以后的数字中寻找。找到数字5后再一次push进栈,这个时候5就是位于栈顶,可以被pop出来。接下来希望被pop的三个数字是3,2,1。每次操作前都位于栈顶,直接pop即可。   再来看序列4、3、5、1、2。pop数字4的情况和前面一样。把4 pop出来之后,3位于栈顶,直接pop。接下来希望pop的数字是5,由于5不是栈顶数字,我们到push序列中没有被push进栈的数字中去搜索该数字,幸运的时候能够找到5,于是把5 push进入栈。此时pop 5之后,栈内包含两个数字1、2,其中2位于栈顶。这个时候希望pop的数字是1,由于不是栈顶数字,我们需要到push序列中还没有被push进栈的数字中去搜索该数字。但此时push序列中所有数字都已被push进入栈,因此该序列不可能是一个pop序列。   也就是说,如果我们希望pop的数字正好是栈顶数字,直接pop出栈即可;如果希望pop的数字目前不在栈顶,我们就到push序列中还没有被push到栈里的数字中去搜索这个数字,并把在它之前的所有数字都push进栈。如果所有的数字都被push进栈仍然没有找到这个数字,表明该序列不可能是一个pop序列。   基于前面的分析,我们可以写出如下的参考代码:   #include <stack> ///////////////////////////////////////////////////////////////////////////// // Given a push order of a stack, determine whether an array is possible to // be its corresponding pop order // Input: pPush – an array of integers, the push order // pPop – an array of integers, the pop order // nLength – the length of pPush and pPop // Output: If pPop is possible to be the pop order of pPush, return true. // Otherwise return false ///////////////////////////////////////////////////////////////////////////// bool IsPossiblePopOrder(const int* pPush, const int* pPop, int nLength) { bool bPossible = false; if(pPush && pPop && nLength > 0) { const int *pNextPush = pPush; const int *pNextPop = pPop; // ancillary stack std::stack<int> stackData; // check every integers in pPop while(pNextPop – pPop < nLength) { // while the top of the ancillary stack is not the integer // to be poped, try to push some integers into the stack while(stackData.empty() || stackData.top() != *pNextPop) { // pNextPush == NULL means all integers have been // pushed into the stack, can’t push any longer if(!pNextPush) break; stackData.push(*pNextPush); // if there are integers left in pPush, move // pNextPush forward, otherwise set it to be NULL if(pNextPush – pPush < nLength – 1) pNextPush ++; else pNextPush = NULL; } // After pushing, the top of stack is still not same as // pPextPop, pPextPop is not in a pop sequence // corresponding to pPush if(stackData.top() != *pNextPop) break; // Check the next integer in pPop stackData.pop(); pNextPop ++; } // if all integers in pPop have been check successfully, // pPop is a pop sequence corresponding to pPush if(stackData.empty() && pNextPop – pPop == nLength) bPossible = true; } return bPossible; }   http://zhedahht.blog.163.com/blog/static/25411174200732102055385/    或者判断出栈序列是否合法   输入两个整形序列,*put,*out,分别表示入栈和出栈,判断出栈是否符和入栈要求。 假设入栈为 首先1,2,3,4,5.出栈顺序为4,3,5,1,2 分析:要得到4,则需将1,2,3,4全部入栈,然后pop得到4,输出3,因为栈顶素即为3,直接输出即可。如果要得到5,需要将入栈队列中的5压入栈,然后输出。此时入栈队列已经为空。栈顶素为2,底为1.此时需要输出1,但是要先输出2,错误,则此出栈顺序不合理。   即如果素在栈顶,直接pop得到,若不在栈顶,需要从入栈队列找到她,一直入栈,然后在pop。否则无法顺利。   代码: 这个代码写的还可以  bool Judge(int *put,int *out,int len) {    bool val=false;    if(put&&out&&len>0)    {      int *p=put;      int *q=out;      stack<int> a;     while(q-out<len)    {           while(a.empty()||*q!=a.top())    //如果栈为空或者栈顶素不等于*q  则需寻找         {           if(!p)            break;           a.push(*p);           if(p-put<len)   //判断入栈队列是否含有素              p++;           else              p=NULL;             }           if(*q!=a.top())  //全部入栈后还是不等               break;           a.pop();           q++;    //判断下一个     }      if(a.empty()&&(q-out==len))              val=true;    }   return     val; }     扩展,给出一组数字为出栈队列,求其可能的入栈队列。   分析:可以根据这组数字,全排列出所有组合,然后每一个组合利用上面的函数判别即可,如果true 即输出。   代码:     void fun(int *a,int *begin,int n,int *b)    //全排列求解     {      if(begin-a==n)      {         if(Judge(a,b,n)              for(int i=0;i<n;i++)               cout<<a[i]<<”  满足条件!!”<<endl;      }     else     {        for(int *temp=beign;temp-a<n;temp++)            {             int val=*begin;                 *begin=*temp;                 *temp=val;                 fun(a,begin+1,n,b);                  *temp=*begin;                 *begin=val;              }      }         }   void Show(int *b,int n) {   int *a=new int[n];   for(int i=0;i<n;i++)        a[i]=n[i];     fun(a,a,n,b);    delete []a; }     int main() {     int b[]={4,5,3,2,1};     Show(b,5); }    参考:   http://blog.163.com/m13591120447_1/blog/static/21637918920132270746190/   http://blog.sina.com.cn/s/blog_4ac9f56e01014vcs.html    http://blog.chinaunix.net/uid-21712186-id-1818123.html

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/48137.html

(0)
上一篇 2024年 9月 4日 下午12:10
下一篇 2024年 9月 4日 下午12:14

相关推荐

关注微信