拿到书本后,看了一下,里面的题目并不是太难,都是初级算法,或者有些根本就不用到算法。
在二分查找的知识点中,还是比较新颖的,看来我写的二分一直存在bug啊。在看看其他方面的题目,很多题目还是要总结分享一下的,
第三章的题目全部看完了,自己也写了一下程序进行了优化。部分作者的程序没有看~cpp的变量名太长了,又不是写项目啊~自己添加的名字估计自己以后看比较方便,对于读者来说,估计作用并不是太大。不如写成伪算法,这样更好一点啊。对吧~~~~~~
话说这个完全可以用二进制编程来处理。具体的二进制编程技巧,谷歌搜索下就知道了。只是让别人看到的时候不容易理解。大牛必备。我也是运用很差的一种,组合题目还是可以搞定的。
解法1.下面是做的个字符串包含问题。记得以前竞赛中出现一个计算机二进制位中的循环数,不过是每8次一个循环,看是不是最后2个int数为循环数。解题思路一样。
解法2:.估计大牛就说了,不如写一个循环队列吧。这样指针到最后重新回来对比就好了。循环一次需要统计打一个标兵记录下。第二次末尾就停止。只是对于解法一,使用的空间少了点。
/* 编程之美-字符串移动包含问题 解题: 将s1与s2取出较大的串扩增一倍,然后用较短与其扩增后的字符串循环对比即可 AABCD CDAA true ABCD ACBD false */ #include <iostream> #define bug printf("bug"); using namespace std; const int MAXN=1<<7; char s1[MAXN],s2[MAXN],tmp[MAXN]; int l1,l2,t; void input(){ scanf("%s",s1); scanf("%s",s2); l1=strlen(s1); l2=strlen(s2); //printf("%c %c",s1,l1); } int strcmp(char* s1,char* s2){ int short_s=strlen(s2); for(int i=0;i<((t<<1)-1);i++){ if(s1[i]==s2[0]){ int j=1; for(;j<short_s;j++){ if(s1[i+j]!=s2[j]){ break; } } if(j==short_s) return 1; } } return -1; } void sovle(){ t=l1>=l2?l1:l2; int flag=-1; if(t==l1){ //l1>=l2 for(int i=0;i<l1;i++) s1[i+l1]=s1[i]; flag=strcmp(s1,s2); }else{ for(int i=0;i<l2;i++) s2[i+l1]=s2[i]; flag=strcmp(s2,s1); } if(flag==-1) printf("false\n"); else printf("true\n"); } int main(){ input(); sovle(); return 0; }
这个题目是指一串电话号(每个数字对应一组字符,老版诺基亚按键~),翻译出组合的单词数量
然后将单词的数量通过英语字典对别输出。这一步联网下载字典就行了。
本题写第一步。
ps:作者的程序啊啊啊啊,难于理解,估计我看了半天才明白过来。都加注释了。
本想用dfs的路径输出下来:
存路径,很多很多~~~每个数字对应的字符数的极限和
不存路径,那么就是在叶子节点输出所有叶子组合,然后回退到父节点,然后输出组合。直到根部节点,这样就是所谓的作者的解题思路、也不是什么dfs了。。。
/* 8 2 6 6 7 8 8 3 7 3 2 6 6 */ #include<iostream> using namespace std; const int MAXN=1<<7; int n; char c[10][10]={ "", "", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS",//7 "TUV", "WXYZ"//9 }; int total[10]={0,0,3,3,3,3,3,4,3,4}; int ans[MAXN]; //代表c[][j]的位置 int num[MAXN]; void input(){ scanf("%d",&n); int i=0; while(i<n)scanf("%d",&num[i++]); } /* 复杂度: 每个数字占用字符数量的乘积 循环的操作方向为:向右 递归的操作方向为:向下 共同操作的产生全部组合 递归到终点,输出每个组合代表的数字即可 */ void sovle2(int* num,int* ans,int i,int n ){ if(i==n){ //递归变脸到第i个数 for(int j =0;j<n;j++) //打印递归到的最后一行输出组合 printf("%c", c[num[j]][ans[j]]); printf("\n"); } for(ans[i] = 0; ans[i] < total[num[i]];ans[i]++) //从第i个数字向右循环每次递归输出 sovle2(num, ans, i + 1, n); } void sovle1(){ while(true){ //打印n位数字对应的n个字符串中首位字符 for(int i = 0; i < n; ++ i) printf("%c", c[num[i]][ans[i]]); printf("\n"); //system("pause"); int k = n - 1; //最后一个号码位置 while(k >= 0){//n-1~0 从下到上 if(ans[k] < total[num[k]] - 1){ //j<max j-1 ans[k]++; // 最后一个号码位置c[i][ans[k]]第二个参数增加至~本字符的最后一位 ,跳出循环打印 break; }else{ ans[k] = 0; // k行已经完成输出,回退一行 --k; } } if(k < 0) break; //k从n-1~0完成输出停止外层循环 } } int main(){ input(); //sovle1(); sovle2(num,ans,0,n); return 0; }
/* 2个字符串的相似度问题: 对2个字符串有三种操作,使其相等的最小操作步骤。注意:是最小~,如果次数为x,那么定义为距离,然后相似度就是1/(x+1) 作者书中木有提到,估计让人费解了~~~~不过程序中写的意思就是啦 1.修改其中一个字符串的字符 2.增加 3.删除 算法分析: 1.相同的字符,比较下一位(因为下一位之后的字符串的操作步骤不会比操作本次的步骤多,这是一个贪心选择问题的意味~) 2.不相同的字符进行三种操作,是操作a呢还是操作b,所以有6种选择。这样想其实完全没有必要的。考虑操作后的状态变化就行了。 无论什么操作,最后结果状态一定是三种其中的一个。 1.A=2~lenA B=1~lenB 2.A=1~lenA B=2~lenA 2.A=2~lenA B=2~lenB 所以对于三个操作后的状态进行递归求解,取三种选择的最小值就ok了。 看代码~~~~~~~ a b abdd aebdd travelling traveling */ #include<iostream> using namespace std; char a[100],b[100]; int lenA,lenB; void input(){ scanf("%s",a); scanf("%s",b); lenA=strlen(a); lenB=strlen(b); //printf("%s %s",a,b); } int calStrDis(char* a,int begin_a,int end_a,char* b,int begin_b,int end_b ){ //边界检测 if(begin_a>end_a){ //不满足条件A if(begin_b>end_b) return 0; else return end_b-begin_b+1; //返回修改的字母B的长度,说明A,B没有交集 } if(begin_b>end_b){ if(begin_a>end_b) return 0; else return end_b-begin_a+1; } if(a[begin_a]==b[begin_b]){ //相等返回下一位~n字符串计算 return calStrDis(a,begin_a+1,end_a,b,begin_b+1,end_b); }else{ //三种操作结果 int t1=calStrDis(a,begin_a+1,end_a,b,begin_b,end_b); int t2=calStrDis(a,begin_a,end_a,b,begin_b+1,end_b); int t3=calStrDis(a,begin_a+1,end_a,b,begin_b+1,end_b); return min(t1,min(t2,t3))+1; } } void sovle(){ printf("%.2f\n",1/(1+(double)calStrDis(a,0,lenA-1,b,0,lenB-1))); } int main(){ input(); sovle(); return 0; }
/* 有先跟序列和中跟序列 输出后跟序列 解法: 先跟访问到的是跟,记录位置p 然后递归构造左右子树 将本次跟放到辅助数组s的最后 输出辅助数组s DBACEGF ABCDEFG ACBFGED */ #include<iostream> using namespace std; const int MAXN=1<<7; char s1[MAXN],s2[MAXN],s[MAXN]; void input(){ scanf("%s%s",s1,s2); } void build(int n,char* s1,char* s2,char* s){ if(n<=0) return ; int p=strchr(s2,s1[0])-s2; //划分左右子树位置 build(p,s1+1,s2,s); //左子树,p长度从s1+1,s2+1+p构建,存储在s中 build(n-1-p,s1+1+p,s2+1+p,s+p); //构建右子树,n-1-p的长度,s1+1+p,s2+1+p开始构造,存储s+p中 s[n-1]=s1[0]; } void sovle(){ int n=strlen(s1); build(n,s1,s2,s); printf("%s\n",s); } int main(){ input(); sovle(); return 0; }
= =有米有错的啊啊啊a~~~~