您的位置:首页 > 其它

两个问题:n对括号有多少种匹配方式与与最长递减子序列

2013-10-14 15:39 357 查看
一.n对括号有多少种匹配方式

首先想到的思路就是列出所有可能并对符合条件的进行计数。考虑采用回溯法,即将括号列表看做是字符串,对于字符串i位来说:要么是左括号→ 递归到i+1位;要么是右括号,递归到i+1位。之后所有位都列好后进行判断,是否符合条件。在统计过程中如果某个步骤右括号的数目大于左边括号的数目,或者统计完成后左右括号数目不等,则不符合条件。代码如下。

#include <iostream>
using namespace std;
//微软44题
bool judgeparent(char a[],int n){
int leftnum=0,rightnum=0;
for(int i=0;i<2*n;i++){
if(a[i] == 'l'){
++leftnum;
}
else if(a[i]== 'r'){
++rightnum;
}
if(rightnum > leftnum)
return false;
}
if(leftnum==n && rightnum==n){
return true;
}
else
return false;
}

void calsum(int current,int n,char a[],int &cnt){
if(current == 2*n){
if(judgeparent(a,n)){
++cnt;
}
return;
}
a[current] = 'l';
calsum(current+1,n,a,cnt);
a[current] = 'r';
calsum(current+1,n,a,cnt);
}

int main(){
int n,cnt =0;
cout<<"please input num of parent:"<<endl;
cin>>n;
char *a = (char *)malloc(2*n);
memset(a,0,2*n);
calsum(0,n,a,cnt);
cout<<cnt<<endl;
system("PAUSE");
return 1;
}

测试结果:2,2

二.求数组的最长递减子序列。例如{9,4,3,2,5,4,3,2}最长序列为{9,5,4,3,2}

这道题有两种解法。先看看编程之美提到中的动态规划解法(但对应的题目是求递增序列,其实都是类似的解法)。

比如已经知道5之前的递减序列为9,4,3,2。而5只会和2进行对比来判定是否可以加入递减序列,得到结论:一.9,4,3,2只是之前状态的总结;二.未来的状态只能通过现在状态来影响。所以采用动态规划解法。设定数组Lis[i]表示以a[i]为结尾的最大递减子序列的长度,则Lis[i+1]有两种情况:若a[i+1}大于所有的a[k](k>=0&&k<i+1),则Lis[i+1]为一,否则,若a[i+1]<a[k]且Lis[i+1]<Lis[k]+1,将a[i+1]加入最长递减子序列并更新Lis[i+1]。

最长递减序列的输出:可以在过程中求得最长递减子序列的最后一个数,然后向前递归,满足a[i+1]<a[k]且Lis[i+1]<Lis[k]+1则肯定在最长递减子序列中。代码如下:

#include <iostream>
using namespace std;

void PrintArray(int a[],int Lis[],int pos){
for(int i =pos-1;i>=0;i--){
if( (Lis[pos] = Lis[i]+1) && a[pos]<a[i]){
PrintArray(a,Lis,i);
break;
}
}
cout<<a[pos]<<" ";
}
void FindMaxDecrease(int a[],int n){
int *Lis = (int *)malloc(sizeof(int)*n);
int maxlen = 1;
int pos = 0;
for(int i =0;i<n;i++){
Lis[i] =1;
for(int j=0;j<i;j++){
if(a[i]<a[j] && (Lis[i]<Lis[j]+1)){
Lis[i] = Lis[j]+1;
if(Lis[i]>Lis[pos])
pos = i;
}
}
}
PrintArray(a,Lis,pos);
free(Lis);
}

int main(){
int a[] = {9,4,3,2,5,4,3,2};
FindMaxDecrease(a,8);
system("PAUSE");
return 1;
}

测试结果为9,5,4,3,2

另外一种解法也是用Lis[i]数组表示以a[i]结尾的最长递减子序列,不同的是用二分查找来寻找每个a[i]的插入位置来更新List[i],这样在最后输出时直接通过List[i]来得到最长递减子序列(不知道大牛想出这样的算法出于何种考虑)。代码如下:

#include <iostream>
using namespace std;

int BinarySearch(int a[],int key,int n){
int begin = 0;
int end = n-1;
while(begin <= end){
int mid = (begin+end)>>1;
if(key > a[mid])
end = mid-1;
else if(key < a[mid])
begin = mid+1;
else
return mid;
}
return begin;
}

void FindMaxDecrease(int a[],int n){
int *Lis = (int *)malloc(sizeof(int)*n);
int *temp =(int *)malloc(sizeof(int)*n);
temp[0] =a[0];
Lis[0]	=1;
int templen = 1;
for(int i =1;i<n;i++){
int pos = BinarySearch(temp,a[i],templen);
temp[pos] = a[i];
Lis[i] = pos+1;
if(pos >= templen)
templen++;
}
int maxlen = templen;
for(int i = n-1;i>=0;i--){
if(templen == Lis[i]){
temp[templen-1] = a[i];
templen--;
}
}
for(int i=0;i<maxlen;i++){
cout<<temp[i]<<" "<<endl;
}
free(temp);
free(Lis);
}

int main(){
int a[] = {9,4,3,2,5,4,3,2};
FindMaxDecrease(a,8);
system("PAUSE");
return 1;
}

测试结果为:9,5,4,3,2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐