【编程之美】中的美中不足,谈谈我的理解


拿到书本后,看了一下,里面的题目并不是太难,都是初级算法,或者有些根本就不用到算法。

在二分查找的知识点中,还是比较新颖的,看来我写的二分一直存在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~~~~



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值