算法入门经典第二版 第三章字符串的后续

算法入门经典第二版第三章

1字符串里面的暴力思想以及如何减少循环加快速度
题目 周期串:
求一个字符串的最小周期是多少:
比如abcabcabc最小周期是3,3个一循环,3个一循环;
思想:每次枚举周期,然后判断是否真的是周期第一次找到最小周期,直接输出,return掉
那么如何减少判断次数了
**a.**我们这样想一个周期的话最大时多少,最小又是多少;
不难发现最大的周期时字符串长度的一半最小的话是1
这样就好枚举了;
**b.**什么情况下一定不是周期呢?
答案显而易见,如果长度除不尽周期长度,就不是周期


#include <iostream>
#include <string>
using namespace std;
int main()
{
    
    
	string s;
	cin>>s;
	int i,j;
	for(i=1;i<=s.size()/2;++i)//从1开始枚举周期到长度的一半 
	{
    
    
		if(s.size()%i==0)//如果除掉就可能是周期;除不尽就不是周期直接跳过
		{
    
    
			int ok=1;//标志变量,一开始假设是周期,其实可以用flag
		
			for(j=0;j<=s.size()-i-1;++j)
			{
    
    
				if(s[j]!=s[j+i])
				{
    
    
					ok=0;//不是的话就是假变量设为0
					break; 
				} 	
			}
			if(ok) 
			{
    
    
				cout<<i;
				return 0;
			}
		}
		 
	}
}

2.数数字映射的妙用
输入一个数字判断0 到 9 出现了几次?
思路:
这个写法的话提供一个简单思路和复杂思路
简单思路就是:
从头到尾判断
如果是0 记录0的数组就加一
,是1记录1的数组就加一

超简单的思路(模板)
映射这个我整理在了我的蓝桥杯奇思妙想模板整理的文件,
需要的私我,留言
需要的私我,留言
需要的私我,留言

结果如下在这里插入图片描述
3.打表(算法比赛中一种混分的方法)
什么叫做打表?
所谓打表就是把每个对应的输入,你已经知道这个对应输出是什么,用数组,if语句等组合直接将答案打出直接过编译器
题目~~:具体见书,生成元~~
一个数字就是这个数字本身,它的生成元时这个数字每个位置上的数字之和再加上本身,比如原始元198 生成元时198+1+9+8=216;
思想;
既然一个既有生成元又又原始元,不妨用个结构体将这2个绑定在一起,这样输入一个生成元,就直接输出对应结构体的原始元,这就是打表。

/*生成一个素组,每个包括2个域一个是生成元,一个叫做原始元
然后输入一个生成元输出对应的原始元 


*/
#include <iostream>
using namespace std;
struct node
{
    
    
	int begin;//原始元 
	int end;//生成元 
};
int f(int n)//求出生成元的函数
{
    
    
	int sum=n;
	while(n)
	{
    
    
		sum+=n%10;
		n/=10;
	}
	return sum;
 } 
node p[100005]; 
int main()
{
    
    
	for(int i=0;i<=100000;++i)
	{
    
    
		if(p[f(i)].begin!=0)
		{
    
    
			continue;
		}
		p[f(i)].begin=i;
	}
	int n;
	cin>>n;
	while(n)
	{
    
    
		int b;
		cin>>b;
		cout<<p[b].begin<<endl;
		n--;
	}
}

核心:

if(p[f(i)].begin!=0)
		{
    
    
			continue;
		}
		p[f(i)].begin=i;

这里注意题目是最小生成元,因为有的元它的原始元有许多个。不要被大的生成元更新了,一个想法是如果有原始元了就continue掉,另一个想法是反过来枚举,这样不用判断,直接可以让小的直接更新掉。
第二个:大家一定会想问p[f(i)].begin=i这个公式如何推出来的
其实很简单

我们这样写用begin表示原始元,end为生成元;
p【216】=198在这个上面归纳法归纳出来
因为求的是原始元所以原始元放右边;
216是生成元,198是原始元;
归纳p[生成元].begin=原始元;
生成元又可以表示为f(i);
所以就是p[f(i)]=i;
4.字符常量的运用
题目 :
回文词
具体见《算法入门竞赛经典第二版》50页
思想:
1.判断回文的话可以运用双指针来求解,关于双指针的话有一些小技巧,什么时候出个集合慢慢讲讲
2.利用常量记一下镜像的字母,对应字母的镜像字母应该是什么;

#include <iostream>
#include <string>
using namespace std; 
char jing[]="A   3  HIL JM O   2TUVWXY5"; //表示A到Z的镜像是什么 
int main()
{
    
    
	string s;
	cin>>s;
	int flag=1,flag1=1;//开始假设是回文词,又是镜像词,flag表示是否为回文词,flag1表示是否为镜像词 
	for(int i=0;i<s.size()/2;++i)
	{
    
    
		if(s[i]!=s[s.size()-i-1])
		{
    
    
			flag=0; //不是回文词; 
		 } 
		 if(flag) 
		 {
    
    
		 cout<<"回文词";
			break; 
		 }
		 
	}
	for(int i=0;i<s.size()/2;++i)
	{
    
    

		if(jing[s[i]-'A']!=s[s.size()-i-1])//如果最后一位的词就是前面一个位置的镜像
		{
    
    
			flag1=0;
		}
	
		if(flag1)
		{
    
    
			cout<<"镜像词"<<endl;
			break; 
		}
	}
	
}

这里有个镜像词嵌套了3个中括号,这种是不好的写法,程序任意让人看花 但是更好的写法可以在底下留言
完了完了写了一个小时,差不多写完了,剩下来的放到字符串后续补充吧,会刷一些字符串的题目,进阶一下下,这个星期应该就是刷刷字符串吧
hash,kmp安排一下
喜欢点个赞点个收藏呗

猜你喜欢

转载自blog.csdn.net/m0_51373056/article/details/109297267