拿到书本后,看了一下,里面的题目并不是太难,都是初级算法,或者有些根本就不用到算法。
在二分查找的知识点中,还是比较新颖的,看来我写的二分一直存在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~~~~