算法入门经典第二版第三章
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安排一下
喜欢点个赞点个收藏呗