文章目录
- 1.如果想把一个多位数的各个位表示怎么办?
- 2.如果想知道最长连号 eg.3 5 6 2 3 4 5 6 8 9 ,最长为5;?
- 3.如果题目给了很大的数?
- 4.当遇见很大的数不行的话可以定义在外面?
- 5.各种应用
- 7.t+=(a[i]-'0')*j++;后面的那个 -"0" 是什么意思?
- 8.当gets()时必须用这个头文件#include
- 9.当遇见字母密码向后移动n时,求其后的东西
- 10.控制格式长度宽度小数
- 11.快速幂
- 12.快速排序
- 13.线性筛模板
- 14.回文数
- 15.栈
- 16.队列
- 17.贪心算法
- 18.字符串操作
- 19.提高时间register优化,用于超时
- 20.priority_queue优先队列 按照由小到大顺序或从大到小;
- 21.一个十进制数的二进制末尾是0为偶数,为1时为奇数
- 22.STL
- 23.n=unique(a,a+10)-a;
- 24.最大公约数最小公倍数
- 25.大数
- 26.二分
- 27.深度优先搜索DFS andBFS
- 29.链表
- 30.最大子段和
- 31.背包九讲
- 33.一个棋盘上正长方形数
- 34.一数前各个数约数和sum?
- 35.比较两字符串是否相同
- 36.满足s =(a + b)* (a - b)时
- 37.二叉树
- 37.并查集
- 38.树状数组
- 39.对N!质因数分解
- 40.均分一组数最小移动
- 41.小A点菜搜索和背包
- 42.字符串匹配
- 43.各种判断函数
- 44.文件输入输出
- 45."1234567891011121314......" 输入N ,s += to_string(i);
- 47.map构建hash
- 48.求只出现一次的数字
- 49.开辟动态数组空间int *dp= new int[n+1];
- 50.string中的replace替换
- 51.二分法求近似值
- 52. “.”和“-> ”的区别
- 53、排序去重
- 000.小知识
![img](https://i-blog.csdnimg.cn/blog_migrate/f9785824c141db0cb8917e6f982debb9.png)
1.如果想把一个多位数的各个位表示怎么办?
while(j>0){
k=j%10;
......j=j/10;
}
2.如果想知道最长连号 eg.3 5 6 2 3 4 5 6 8 9 ,最长为5;?
m=0;
k=0;
for(int i=1;i<n;i++)
{
if(a[i]+1==a[i+1])m++;
else {k++; 切记弄一个k++,用一个b[i]
b[k]=m+1;m=0
3.如果题目给了很大的数?
切记用 long long
4.当遇见很大的数不行的话可以定义在外面?
long long a[100000000],b[10000000];
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SuhGpQYo-1574958449322)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1544709286131.png)]
5.各种应用
#include
##6.include //不要忘记包含此头文件
using namespace std;
int main()
{
1. int a;
2. cout<<"input a:";
3. cin>>a;
4. cout<<"dec:"<<dec<<a<<endl; //以十进制形式输出整数
5. cout<<"hex:"<<hex<<a<<endl; //以十六进制形式输出整数a
6. cout<<"oct:"<<setbase(8)<<a<<endl; //以八进制形式输出整数a
7. char *pt="China"; //pt指向字符串"China"
8. cout<<setw(10)<<pt<<endl; //指定域宽为,输出字符串
9. cout<<setfill('')<<setw(10)<<pt<<endl; //指定域宽,输出字符串,空白处以''填充
10. double pi=22.0/7.0; //计算pi值
11. //按指数形式输出,8位小数
12. cout<<setiosflags(ios::scientific)<<setprecision(8);
13. cout<<"pi="<<pi<<endl; //输出pi值
14. cout<<"pi="<<setprecision(4)<<pi<<endl; //改为位小数
15. cout<<"pi="<<setiosflags(ios::fixed)<<pi<<endl; //改为小数形式输出
16. return 0;
##7.进制的互相转化.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o8DPU2mS-1574958449322)(file:///C:\Users\asus\Documents\Tencent Files\2035756541\Image\C2C\1C82D1214C2BD67805FD8C9E1A2BCE1F.jpg)]
//***将十进制化为二进制
#include<bitset>
cout<<bit<sizeof(n*2)>(n)<<endl;//2.4.8控制几位;
//化为八进制十六进制
cout<<oct<<n<<endl;
cout<<hex<<n<<endl;
cout<<“重回十进制”<<dec<<n<<endl;
7.t+=(a[i]-‘0’)*j++;后面的那个 -“0” 是什么意思?
应该是把字符型数据转换为整型,在ACSII码表中,字符‘0’的十进制值是48,假设有一个字符为‘0’,那么计算机识别出来的十进制值是48,而不是0。所以可以通过问题上的公式可以把字符型的0转化为整型的0。同理,可以把1到9的字符转换成整型的1到9,看一下ASCII码表就懂了,不难的。通俗来讲就是一个数据类型的转换,这种操作在单片机上的数据转换用得会比较多,但一般是反过来用,把十进制的整型数字转换成字符型数字,然后在一些显示设备上打印出来。
#include <stdio.h>//代码简洁明了(个人观点)
int main(void){
char a[14], mod[12] = "0123456789X"; //先将mod11后的十一个字符存入数组
gets(a); //输入字符串
int i, j = 1, t = 0;
for(i = 0; i < 12; i++) {
if(a[i] == '-') continue; //字符串为分隔符‘-’时跳过此次循环进入下一次循环
t += (a[i]-'0')*j++; //t储存 第j个 数字 * j 的和
}
if(mod[t%11] == a[12]) printf("Right");
else {
a[12] = mod[t%11]; //若识别码错误,则赋正确的识别码,然后输出
puts(a);
}
return 0;
}
C语言的数组并不是“一等公民”,而是“受歧视”的。例如,数组不能够进行赋值操作:
在程序3-1中,如果声明的是“int a[maxn],b[maxn]”,是不能赋值b=a的。如果要从数组a复
制k个元素到数组b,可以这样做:memcpy(b,a,sizeof(int) * k)。当然,如果数组a和b
都是浮点型的,复制时要写成“memcpy(b,a,sizeof(double) * k)”。另外需要注意的是,
使用memcpy函数要包含头文件string.h。如果需要把数组a全部复制到数组b中,可以写得简单
一些:memcpy(b,a,sizeof(a))。
8.当gets()时必须用这个头文件#include
#include<iostream>
#include<cstring>
#include<cstdio> //当gets()时必须用这个头文件,不然过不了。
using namespace std;
int main()
{char a[10],b[10];
gets(a);
gets(b);
int sum=1;
for(int i=0;i<strlen(a);i++){
sum=sum*(a[i]-64);}
int sum2=1;
for(int j=0;j<strlen(b);j++){
sum2=sum2*(b[j]-64);
}
if(sum%47==sum2%47)cout<<"GO"<<endl;
else cout<<"STAY"<<endl;
return 0;
}
9.当遇见字母密码向后移动n时,求其后的东西
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
int n,t;
char a[50];
cin>>n>>a; //当输入一个字符串时也可以char a[50]; cin>>a;
for(int i=0;i<strlen(a);i++){
putchar((a[i]-'a'+n)%26+'a'); //主要的移动算法,当移动到末尾会从头开始的
}
return 0;
}
10.控制格式长度宽度小数
#include <iostream>
#include <iomanip>
int main()
{
cout<<"第一章"<<endl;
cout<<" ";
cout<<setiosflags(ios::left)<<setw(7); //设置宽度为7,left对齐方式
cout<<"1.1";
cout<<"什么是C语言";
cout<<resetiosflags(ios::left); //取消对齐方式
cout<<setfill('.')<<setw(30)<<1<<endl; //宽度为30,填充为'.'输出
cout<<setfill(' '); //恢复填充为空格
cout<<" ";
cout<<setw(7)<<setiosflags(ios::left); //设置宽度为7,left对齐方式
cout<<"1.11";
cout<<"C语言的历史";
cout<<resetiosflags(ios::left); //取消对齐方式
cout<<setfill('.')<<setw(30)<<58<<endl; //宽度为30,填充为'.'输出
cout<<setfill(' ')<<"第二章"<<endl;
return 0;
}
cout<<fixed<<setprecision(7)<<endl; //控制小数时;
11.快速幂
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6aHtXxEJ-1574958449323)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551578583126.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c4j7iS5a-1574958449323)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551578615551.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D3hFOQTq-1574958449324)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551578651736.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPAFyy4x-1574958449324)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551578680783.png)] 快速幂模板 !
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VSow6sK5-1574958449324)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551579554668.png)]快速幂
int f(int a,int b,int m){
if(b==0)return 1;
if(b%2==1){
return a*f(a,b-1,m)%m;
}
else {
int t=f(a,b/2,m);
return t*t%m;
}
}
12.快速排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wtq8t791-1574958449325)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551580696497.png)]
sort(a,a+n) // 快速排序,无大小顺序;
当有大小顺序时用:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKEx7dFj-1574958449325)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551581119543.png)]
#include<iostream>
#include<algorithm> //函数头
#define N 10000051
int a[N];
using namespace std;
int cmp(int a,int b){
return a<b; //a<b是升序,a>b是降序
}
int main()
{ int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n,cmp); //配函数头用来升降序
for(int i=0;i<n;i++){
cout<<a[i];
}
return 0;}
13.线性筛模板
- 判断素数!
需要头文件:
bool isprime(int x)
{
int n = sqrt(x)+0.5; // 假如sqrt(9)返回2.999999999,n=2,结果可就错了。
for (int i=2;i<=n;i++)
if (x%i==0) return false;
return true;
}
两个优化:
① 质数除了 2 都是奇数。所以除了 2,只判断奇数因数就可以了。
② 先在素数表内找因数,如果质数表内的最大因数仍未达到 x,再继续枚举。如果这个数是素数,就加
入到素数表中。
-
筛法产生素数表!
#include<iostream> using namespace std; #include<cstring> #define N 10000000 bool a[N]; int b[N],n=0; void f(){ int i;int j; memset(a,0,sizeof(a)); for ( i=2;i<N;i++) if (!a[i]) { b[n++]=i; for ( j=i+i;j<N;j+=i) a[j]=true; } } int main() { f(); for(int i=0;i<=1000000;i++){ cout<<b[i]<<endl; } }
素数线性筛
#include<iostream>
#include<cstring>
using namespace std;
#define N 1000000
bool a[N];
int b[N];
int f(){int i,j,n=0;
memset(a,0,sizeof(a));
for(i=2;i<N;i++){
//未标记的则得到一个为素数
if(a[i]==0){
b[n++]=i;
}
//标记目前得到素数的i倍为非负数
for(j=0;j<n&&i*b[j]<N;j++){
a[i*b[j]]=1;
if(i%b[j]==0)break;
}
}
}
int main(){
int x;
cin>>x;
f();
for(int i=0;i<x;i++){
cout<<b[i]<<' ';
}
return 0;
}
bool visited[N]; // 如果被筛,设为true
int primes[N], n=0; // 素数表
memset(visited,0,sizeof(visited));
for (i=2;i<N;i++)
if (!visited[i])
{
primes[n++]=i;
for (j=i+i;j<N;j+=i) visited[j]=true;
} //这种筛法虽然有点“朴素”,但是已经够用了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0RYINLZ-1574958449326)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1551581203454.png)]
14.回文数
bool huiwen(int x){
int y=x,num=0;
while(y!=0){
num=num*10+y%10;
y/10;
}
if(num==x)return 1;
}
15.栈
1 #include <iostream>
2 #include <stack> //栈的函数头
3 using namespace std;
4
5 int main()
6 {
7
8 stack<int> s; //定义栈
9 s.push(1); //s.push(a);叫压栈
10 s.push(2); //同上
11 s.push(4); //同上
12 s.push(5); //同上
13
14 cout << s.size() << endl; //s.size();判断栈中元素的个数
15
16 while(s.empty() != true) //s.empty();判断栈是否为空
17 {
18 cout << s.top() << endl; //s.top();取出栈顶元素
19 s.pop(); //s.pop();弹出栈顶元素
20 }
21 return 0;
22 }
将进栈出栈与数组连接起来
#include<iostream>
using namespace std;
#include<stack>
int main(){
stack<int>s;
int n,a[100];
cin>>n;
for(int i=0;i<n;++i)
{cin>>a[i];
s.push(a[i]);
}
cout<<s.size()<<endl;
while(s.empty()==NULL){
cout<<s.top()<<endl;
s.pop();
}
return 0;
}
16.队列
queue有入队push(插入)、出队pop(删除)、读取队首元素front、读取队尾元素back、empty,size这几种方法
priority_queue(最大元素先出)
#include <iostream>
#include <queue>
using namespace std;
int main()
{
priority_queue<int> pq;
pq.push(1);
pq.push(3);
pq.push(2);
pq.push(8);
pq.push(9);
pq.push(0);
cout << "size: " << pq.size() << endl;
while(pq.empty() != true)
{
cout << pq.top() << endl;
pq.pop();
}
return 0;
}
队列与数组结合
#include<iostream>
using namespace std;
#include<queue>
int main(){
queue<int>s;
int n,a[100];
cin>>n;
for(int i=0;i<n;++i)
{cin>>a[i];
s.push(a[i]);
}
cout<<s.size()<<endl;
while(s.empty()==NULL){
cout<<s.front()<<endl;
s.pop();
}
return 0;
}
17.贪心算法
18.字符串操作
头文件:。printf 和 scanf 在中,cin 和 cout 在头文件中且位于
std 命名空间内。
下面假设待处理的字符串为 str 和 str2,即:char str[MAX], str2[MAX];
牢记, 字符串的最后一个字符一定是’\0’。如果字符串内没有’\0’,进行以下操作(输入除外)时可能
会造成意外事故。
-
输出字符串 str:
cout<<str;
printf("%s",str); // 输出到文件:fprintf(fout, “%s”, str); -
输入字符串 str:
scanf("%s", str); // 输出到文件:fscanf(fin, “%s”, str);
cin>>str;
以上两种方法在输入时会忽略空格、回车、TAB 等字符,并且在一个或多个非空格字符后面输入空格
时,会终止输入。
fgets(str, MAX, fin);
每调用一次,就会读取一行的内容(即不断读取,直到遇到回车停止)。 -
求字符串 str 的 长度:strlen(str) // 这个长度不包括末尾的’\0’。
-
把串 字符串 str2 连接串 到字符串 str 的末尾:strcat(str, str2)
str 的空间必须足够大,能够容纳连接之后的结果。
连接的结果直接保存到 str 里。函数返回值为&str[0]。
strncat(str, str2, n)是把 str2 的前 n 个字符连接到 str 的末尾。 -
把字符串 str2 复制 到串 字符串 str 中 :strcpy(str, str2)
-
比较 str 和 和 str2 的大小:strcmp(str, str2)
如果 str>str2,返回 1;如果 str==str2,返回 0;如果 str<str2,返回-1。 -
在 在 str 中寻找符 一个字符 c :strchr(str, c)
返回值是一个指针,表示 c 在 str 中的位置。用 strchr 的返回值减 str,就是具体的索引位置。
- 在 在 str 中寻找 str2 :strstr(str, str2)
返回值是一个指针,表示 str2 在 str 中的位置。用 strstr 的返回值减 str,就是具体的索引位置。
此问题可以用 KMP 算法解决。KMP 算法很复杂,在 NOIP 范围内用途不大。
- 从 从 str 中获取数据:sscanf(str, “%d”, &i);
格式化字符串:sprintf(str, “%d”, i);
它们和 fscanf、fprintf 非常像,用法也类似。可以通过这两个函数进行数值与字符串之间的转换。
- 大小写转化
a[0]=toupper(a[0]);转换为大写
a[i]=tolower(a[i]); 转换为小写
- 是否为子串
```c
#include <stdio.h>
#include <string.h>
#define N 200
char A[N], B[N];
int main()
{
char *r1,*r2;
scanf("%s %s",A,B);
r1=strstr(B,A);
r2=strstr(A,B); //char *r1,*r2;
if(r1!=NULL) //strstr(B,A);
printf("%s is substring of %s\n", A, B);//A是B的子串,r1不为空
else if (r2 != NULL)
printf("%s is substring of %s\n", B, A);
else
printf("No substring\n");
return 0;
}
```
19.提高时间register优化,用于超时
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mzCxQ8qU-1574958449328)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1552182762312.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pokq8LIn-1574958449329)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1552186172788.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s5MrM74y-1574958449329)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1552186222359.png)]
20.priority_queue优先队列 按照由小到大顺序或从大到小;
#include<queue>
int main(){
priority_queue<int ,vector<int>,greater<int> q;
priority_queue<int ,vector<int>,less<int> q;
return 0;
}
21.一个十进制数的二进制末尾是0为偶数,为1时为奇数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ARV5PRqc-1574958449329)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1552841895938.png)]
22.STL
#include<algorithm>
1. fill()//可以把数组中某一段替为某个值
fill(a,a+5,233)
2. max(a,b);
min(a,b);
abs(a);
swap(a,b);
reverse(a,a+n);//用来反转;
3. next_permutation //全排列;
do{
cout<<a[1]<<a[2]<<a[3]<<endl;
}while(next_permutation(a,a+3));
23.n=unique(a,a+10)-a;
先sort再用其是将重复段去掉后的长度;
24.最大公约数最小公倍数
最大公约数
1. int f(int a,int b) //前提a>b;
{if(b==0)retunr a;
else retunr f(b,a%b);
}
2. int f(int a,int b){
return b==0? a:f(b,a%b);
}
最小公倍数为
a/d*b;//d为最大公约数
25.大数
-
大数加法:
-
-
#include<iostream> using namespace std; #include<string> #define L 1000 string add(string a, string b) { string ans; int na[L] = {0}, nb[L] = {0}; int la = a.size(), lb = b.size() ; for(int i = 0; i < la; i++) { na[la - i - 1 ] = a[i] - '0'; } for(int i = 0; i < lb; i++) { nb[lb - i - 1 ] = b[i] - '0'; } int lmax = la > lb ? la : lb; for(int i = 0; i < lmax; i++) { na[i] += nb[i]; na[i + 1] += na[i] / 10; na[i] %= 10; } if(na[lmax]) lmax ++; for(int i = lmax - 1; i >= 0; i-- ) { ans += na[i] + '0'; } return ans; } int main(){ string a; string b; while(cin >> a >> b){ cout << add( a , b ); } return 0; }
-
大数阶乘
#include<iostream>
using namespace std;
#include<cstring>
int main(){
int num[100]={0};
num[0]=1,num[1]=1;
int n;cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=num[0];j++){
num[j]*=i;
}
for(int j=1;j<=num[0];j++){
if(num[j]<10){
continue;}
num[j+1]+=num[j]/10;
num[j]%=10;
num[0]+=(j==num[0]);
}
}
for(int i=num[0];i>0;i--){
cout<<num[i];
}
return 0;
}
26.二分
#include<iostream>
using namespace std;
int f(int a[],int x,int n){
int l=0,r=n-1,mid;
while(l<=r){
mid=(l+r)>>1;
if(a[mid]==x)return mid;
if(a[mid]>x) l=mid-1;
else r=mid+1;
}
return -1;
}
int main(){
int a[10]={1,2,3,4,5,6,7,8,9,10};
int t=f(a,5,10);
cout<<t;
}
// 111111000000
int binary_search1(int *num, int n) {
int l = -1, r = n - 1, mid;
while (l < r) {
mid = (l + r + 1) >> 1;
if (num[mid] == 1) l = mid;
else r = mid - 1;
}
return l;
}
// 0000001111111
int binary_search2(int *num, int n) {
int l = 0, r = n, mid;
while (l < r) {
mid = (l + r) >> 1;
if (num[mid] == 1) r = mid;
else l = mid + 1;
}
return l == n ? -1 : l;
}
#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
int a[5] = {2, 4, 6, 8 ,10};
int w = std::lower_bound(a, a + 5, 8) - a; // 查找第一个大于等于的值
cout << a[w] << endl;
int s = std::upper_bound(a, a + 5, 8) - a; // 查找第一个大于的值
cout << a[s] << endl;
return 0;
}
27.深度优先搜索DFS andBFS
“模板”:
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意添加
return;
}
if(越界或者是不合法状态)
return;
if(特殊状态)//剪枝
return ;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
修改操作;//根据题意来添加
标记;
dfs();
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
void DFS(int depth)
{
if (depth==n) // 深度超过范围,说明找到了一个解。
{
// 找到了一个解,对这个解进行处理,如:输出、解的数量加1、更新目前搜索到的最优值等
return;
}
// 扩展结点,如
for (int i=0; i<n; i++)
{
// 处理结点
…
// 继续搜索
DFS(depth+1);
// 部分问题需要恢复状态,如N皇后问题
…
}
}
1.记忆化斐波那契数列(记忆化版)
int f[MAX_N] = {0};
int func(int n) {
if (f[n] != 0) return f[n];
if (n <= 2) return (f[n] = 1);
else return (f[n] = func(n - 2) + func(n - 1));
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mUdMyu1L-1574958449330)(D:\我的文档\Documents\Tencent Files\2035756541\FileRecv\MobileFile\IMG20190425191659.jpg)]
#include<iostream>
using namespace std;
#define max 30
long long int f[max][max][max]={0};
long long int w(long long int a,long long int b,long long int c){
if(a<=0||b<=0||c<=0)return 1;
if(a>20||b>20||c>20){return w(20,20,20);}//return 此处不用标记
if(f[a][b][c]!=0)return f[a][b][c];
if(a<b&&b<c) {
f[a][b][c]=w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c);
return f[a][b][c];}
f[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
return f[a][b][c];
}
int main(){
long long int x, y ,z;
while(cin >> x>> y>> z){
if(x == -1&&y == -1&&z == -1)break;
cout <<"w("<<x<<", "<<y<<", "<<z<<") = "<<w(x,y,z)<<endl;}
return 0;
}
- N皇后问题
#include<iostream>
using namespace std;
#include<cstring>
bool column[20],cross1[50],cross2[50];
int pos[20];
int n,sum=0;
void dfs(int row)
{
if(row==n)
{
sum++;
return ;
}
for(int i=0;i<n;i++)
if(!(column[i]||cross1[row-i+n]||cross2[row+i]))//判断是否可以放置皇后
{ //对皇后已经控制的列和对角线做标记
column[i]=cross1[row-i+n]=cross2[row+i]=true;
pos[row]=i;
dfs(row+1);
column[i]=cross1[row-i+n]=cross2[row+i]=false;
}
}
int main(){
cin>>n;
memset(column,0,sizeof(column));
memset(cross1,0,sizeof(cross1));
memset(cross2,0,sizeof(cross2));
dfs(0);
cout<<sum<<endl;
return 0;
}
迷宫问题:
#include<iostream>
using namespace std;
int n, m;
#include<queue>
typedef struct var{
int x,y;
int z;
}Node;
queue<Node>travel;
int vis[4][2] = {1,0,-1,0,0,1,0,-1};
char map[100][100];
int book[100][100] = {0};
int bfs(Node start)
{
Node ele, temp;
travel.push(start);
while(travel.size()){
int dx, dy;
ele = travel.front();
travel.pop();
for(int i = 0; i < 4; i++) {
dx = ele.x + vis[i][0];
dy = ele.y + vis[i][1];
if(dx < n&&dy < m &&dy >= 0&&dx >= 0&&book[dx][dy] == 0&&map[dx][dy] == '.'){
book[dx][dy] = 1;
temp.x = dx;
temp.y = dy;
temp.z = ele.z + 1;
travel.push(temp);
}
if(map[dx][dy]=='.'){
if(dx + 1 >= n||dx - 1 < 0||dy + 1 >= m|| dy - 1 < 0 ){
return ele.z + 1;
}
}
}
}
return -1;
}
int main()
{
Node start;
cin >> n >> m;
for(int i = 0; i < n; i ++) {
for(int j = 0; j < m; j++) {
cin >> map[i][j];
if(map[i][j] =='@'){
start.x = i;
start.y = j;
}
}
}
start.z = 0;
int ans = bfs(start);
cout << ans <<endl;
return 0;
}
##28.数据结构
v- >data = (int *)malloc(sizeof(int )*n)
#include<iostream>
#include<stdio.h>
using namespace std;
#include<stdlib.h> //声明结构体
typedef struct Vector{
int *data; //开辟空间
int size, length;//多大多长
}Vector;
void init (Vector *v, int n)//初始化
{
v->data = (int *)malloc(sizeof(int)*n);//动态空间开辟
v->size = n;
v->length = 0;
return ;
}
//扩容
int expand(Vector *v){
int *p = (int *)realloc(v->data, sizeof(int )* v->size*2);
if(p == NULL) {
return 0;// 如果开辟失败相当于没开
}
v->data = p;
v->size = v->size*2;
return 1;
}
// 插入
int insert(Vector *v ,int ind,int value) {//插入位置不合法
/*if(v->length == 0){//pan duan shu xu biao shi fou he fa ;
return 0;
}*/
if( ind <0||ind > v->length){// 判断插入是否合法
return 0; //cout<<"bu he fa"<<endl;
}
if(v->length >= v->size){
expand(v);
return 0;
}
for(int i = v->length;i > ind; --i )//插入往后移
{
v->data[i] = v->data[i-1];
}
v->data[ind] = value;
v->length++;
return 1;
}
// 删除
int erase(Vector *v, int ind) { // 删除
if(v->length == 0 ) {
return 0;
}
if(ind < 0 || ind >= v->length) {
return 0;
}
for(int i = ind + 1;i < v->length; i++){
v->data[i-1]=v->data[i];
}
v->length -= 1; //删除最后一位
return 1;
}
//查找
int search(Vector *v,int value) {
for(int i=0 ; i< v->length;i++){
if(v->data[i] == value) {
return 1;
}
}return 0;
}
// 遍历
void output(Vector *v) {
for(int i=0; i< v->length;i++){
if(i==0) {
printf("%d", v->data[i]);
}
printf("%d ", v->data[i]);
}
printf("\n");
return ;
}
//清除;
void clear(Vector *v){
if( v == NULL)return ;
free(v->data);
free(v);
return ;
}
#define MAX_N 30
int main()
{
Vector *v = (Vector *)malloc(sizeof(Vector));
init(v, MAX_N);
int ind, value;
int n, t;
scanf("%d", &n);
for(int i = 0; i < n;i++)
{
scanf("%d %d", &ind, &value);
insert(v, ind, value);
}
output(v);
erase(v, 3);
output(v);
if(search(v, 4)){
cout<<"success";
}else {
cout<<"faile";
}
clear(v);
return 0;
}
29.链表
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct Linklist{
int data;
Linklist *next;
};
Linklist *creat(int n)
{
Linklist *head, *end, *node;
head = new Linklist;
end = head;
for(int i = 0; i < n; i++)
{
node = new Linklist;
cin >> node->data;
end->next = node;
end = node;
}
end->next = NULL;
return head;
}
void change(Linklist *list, int n) // n为第n个节点
{
Linklist *t = list;
int i = 0;
while(i < n && t !=NULL ){
t = t ->next;
i++;
}
if(t!=NULL){
cout<<"输入修改的值";
cin >> t->data;
}
else cout<<"节点不存在"<<endl;
}
void deleat(Linklist *list, int n)
{
Linklist *t =list,*in;
int i = 0;
while(i < n&& t!=NULL)
{
in = t;
t = t->next;
i++;
}
if(t!=NULL){
in->next = t->next;
free(t);
}
else {
cout<<"节点不存在"<<endl;
}
}
void insert(Linklist *list, int n){
Linklist *t = list,*in;
int i = 0;
while( i < n&&t != NULL){
t = t->next;
i++;
}
if(t != NULL){
in = new Linklist;
cout<<"输入插入的值";
cin >> in->data;
in->next = t->next;
t->next = in;
}
else {
cout<<"节点不存在"<<endl;
}
}
int main()
{
int n,w ;
cin >> n;
Linklist *x;
x = creat(n)->next;
cout<<"修改的第几个节点";
cin >> w;
change(x,w);
int s;
cout<<"删除的节点";
cin >> s;
deleat(x,s);
int a;
cout<<"需要插到哪位";
cin >>a;
insert(x,a);
while(x != NULL)
{
cout<<x->data<<' ';
x = x->next;
}
return 0;
}
30.最大子段和
若记b[j]=max(a[i]+a[i+1]+…+a[j]),其中1<=i<=j,并且i<=j<=n。则所求的最大子段和为max b[j],1<=j<=n。
由b[j]的定义可易知,当b[j-1]>0时b[j]=b[j-1]+a[j],否则b[j]=a[j]。故b[j]的递推方程为:
b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n。
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{ int n;
cin >> n;
int a[200005] = {0};
int b[200005] = {0};
for(int i = 0; i<n ; i++) {
scanf("%d",&a[i]);
}
b[0] = a[0];
int max;
max = b[0];
for(int i = 1; i<n; i++) {
if(b[i - 1] > 0){
b[i] = b[i - 1] + a[i];
}
else {
b[i] = a[i];
}
if(b[i] > max){
max = b[i];
}
}
cout << max <<endl;
return 0;
}
动态规划转移方程
#include<iostream>
using namespace std;
int a[10000000];
int dp[10000000];
int n;
#include<algorithm>
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n ;i++) {
dp[i] = max(dp[i - 1] + a[i], a[i] );
}
sort(dp + 1, dp + n + 1);
cout << dp[n]<<endl;
return 0;
}
31.背包九讲
-
背包问题(每件只有一件放或不放)
n件物品装V容量包里,第i件物品费用c[i],价值w[i];
转移方程
f[i][v] = max{f[i - 1][v], f[i - 1][v - c[i]] + w[i]}
for(int i = 1; i<=n; i++) { for(int j = v; j>= c[i]; j--) { f[j] = max(f[j] , f[j - c[i]] + w[i]);//求最大价值 } } f[j] = max(f[j], f[j - c[i]] + c[i])//求最大体积
-
完全背包问题(每件物品有无限件可放)
for(int i = 1; i<=n; i++) {
for(int j = c[i]; j<= v; j++) { //和1中的区别
f[j] = max(f[j] , f[j - c[i]] + w[i]);
}
}
eg:
#include<iostream>
using namespace std;
int f[100101];
int c[100001];
int w[100001];
#include<algorithm>
int main()
{
int m,n;
cin >> m >> n;
for(int i = 1; i <= n; i++) {
cin >> c[i] >> w[i];
}
for(int i = 1 ; i <= n; i++) {
for(int j = c[i]; j <= m; j++) {
f[j] = max(f[j], f[j - c[i]] + w[i]);
}
}
cout << f[m] <<endl;
return 0;
}
##32.卡罗兰数
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …
令h(0)=1,h(1)=1,catalan数满足递推式 [2] :
**h(n)= h(0)*h(n-1)+h(1)h(n-2) + … + h(n-1)h(0) (n>=2)
例如:h(2)=h(0)h(1)+h(1)h(0)=11+11=2
h(3)=h(0)h(2)+h(1)h(1)+h(2)h(0)=12+11+21=5
h(n)=h(n-1)*(4*n-2)/(n+1);
递推关系的解为:
h(n)=C(2n,n)/(n+1) (n=0,1,2,…)
递推关系的另类解为:
h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,…)
1、进出栈问题:栈是一种先进后出(FILO,First In Last Out)的数据结构.如下图1,1,2,3,4顺序进栈,那么一种可能的进出栈顺序是:1In→2In→2Out→3In→4In→4Out→3Out→1Out, 于是出栈序列为1,3,4,2。
那么一个足够大的栈的进栈序列为1,2,3,⋯,n时有多少个不同的出栈序列?
我们可以这样想,假设k是最后一个出栈的数。比k早进栈且早出栈的有k-1个数,一共有h(k-1)种方案。比k晚进栈且早出栈的有n-k个数,一共有h(n-k)种方案。所以一共有h(k-1)*h(n-k)种方案。显而易见,k取不同值时,产生的出栈序列是相互独立的,所以结果可以累加。k的取值范围为1至n,所以结果就为h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)h(0)。
33.一个棋盘上正长方形数
-
x=min(m,n)-1
-
长方形里面数正方形的个数计算公式:mn+(m-1)(n-1)+…+(m-x)*(n-x)
-
mn表示长度为1的正方形的个数,(m-1)(n-1)表示长度为2的正方形的个数。。。。。。
-
//长方形里面数长方形的个数计算公式(包含正方形):(1+2+3+…+m)(1+2+3+…+n)=nm(n+1)*(m+1)/4
#include<iostream>
using namespace std;
int main(){
long long int n, m;
cin >> n >> m;
long long int sum = 0;
long long int l = n;
long long int t = m;
if(n > m) {
for(int i = m - 1; i >= 0; i--) {
sum += (n - i)* (m - i);
}
}else {
for(int i = n - 1; i >= 0; i--) {
sum += (n - i)*(m -i);
}
}
cout << sum<<' ';
cout << ( (l * 1ll*t * (l + 1)*(t + 1)) / 4) - sum <<endl;
return 0;
}
34.一数前各个数约数和sum?
for(int i = 1; i<=n ;i++) {
sum += n / i;
}
35.比较两字符串是否相同
但在比较两个string对象时是可以利用“==”的,相等的话,则表达式的返回值为1,不等为0。
#include<iostream>
#include<cstring>
using namespace std;
int main() {
char a[] = "aaa",b[]="aaa";
string A = "AAA", B = "AAA";
cout <<"*a和*b的值分别是:" <<*a << "," << *b << endl;
cout <<"*“aaa”的值是:"<< *"aaa" << endl;
cout <<"利用 == 比较a,b两个字符串,结果是(相等为1,不等为0):" <<(a==b) << endl;
cout << "利用strcmp()比较a,b两个字符串,结果是(相等为0,不等非0):"<<strcmp(a,b) << endl;
cout << "利用 == 比较A,B两个string,结果是(相等为1,不等为0):"<<(A==B) << endl;
cout << "利用compare()比较A,B两个string,结果是(相等为0,不等非0):" << A.compare(B) << endl;
return 0;
}
36.满足s =(a + b)* (a - b)时
| s |必须是四的倍数或者是奇数!
结果:
*a和*b的值分别是:a,a
*“aaa”的值是:a
利用 == 比较a,b两个字符串,结果是(相等为1,不等为0):0
利用strcmp()比较a,b两个字符串,结果是(相等为0,不等非0):0
利用 == 比较A,B两个string,结果是(相等为1,不等为0):1
利用compare()比较A,B两个string,结果是(相等为0,不等非0):0
37.二叉树
【二叉树的定义】
二叉树T:一个有穷的结点集合。这个集合可以为空;若不为空,则它是由根结点和称为其左子树TL和右子树TR的两个不相交的二叉树组成。二叉树的子树有左右顺序之分。
二叉树的五种基本形态:
37.并查集
#include<iostream>
using namespace std;
const int N = 110;
int father[N];//存放父亲节点
bool isroot[N];//记录每个节点是否为某集合的根节点
/*int findfather(int x){
if(x == father[x])return x;
else {
int f = findfather(father[x]);
father[x] = f;
return f;
}
} */
int findfather(int x){
return father[x] == x ? x : father[x];
}
void union(int a, int b){
int faA = findfather(a);
int fbB = findfather(b);
if(faA!=fbB){
father[faA] = faB;
}
}
void init(int n){
for(int i = 1; i <= n; i++) {
father[i] = i;
isroot[i] = false;
}
}
int main()
{
int n, m, a, b;
cin >> n >> m;
init(n);
for(int i = 0; i < m; i++){
cin >> a >> b;
union(a, b); // 合并a, b集合
}
for(int i = 1; i <= n; i++) {
isroot[findfather(i)] = true;
}
int ans = 0;
for(int i = 1; i <= n; i++) {
ans+=isroot[i];
}
cout<< ans <<endl;
return 0;
}
38.树状数组
切入点:lowbit函数
由于电脑一种叫做补码的操作(由于电脑是二进制,它们存的相反数是它的取反+1),一个数与它的相反数做与操作时会返回二进制下最右边的1的位置。举个例子: 6&-6=2 将6变成二进制:110。其中最右侧的1加粗字体:110则返回的是二进制下10的值:2。得到代码:
ll lowbit(ll num){
return num&-num;
}
1.【模板一】
#include<iostream>
using namespace std;
#include<cstring>
long long int n ,m;
const int N = 5000005;
int a[N],c[N];//zhuangtaishuzu
int lowbit(int x){
return x & (-x);
}
void updata(int x, int v){
for(int i = x; i <= n; i+=lowbit(i)){
c[i] += v;
}
}
int getsum (int x){
int sum = 0;
for(int i = x;i > 0; i-=lowbit(i)){
sum +=c[i];
}
return sum;
}
int main()
{
cin >> n >>m;
memset(c, 0 ,sizeof(c));
for(int i = 1; i<=n; i++) {
cin >> a[i];
updata(i,a[i]);
}
int t, l, r;
for(int i = 1; i<=m; i++) {
cin >> t >> l >> r;
if(t == 1){
updata(l,r);
}
else if(t == 2){
cout << getsum(r) - getsum(l - 1) <<endl;
}
}
return 0;
}
2.【模板二】(差分法)
突破口:差分
思考一下,如果区间修改2到4位之后求第3位,我们就可以加上修改的数。而如果求第5位,我们只需要在第3位的基础上减去修改的数就可以了。举个例子:在数组第2位和第4位之间加上2,只需要将数组从0 0 0 0 0变成0 2 0 0 -2即可。当询问第3位时,答案就是输入的3的值+0+2+0即可。当询问5时,答案就是输入的5的值+0+2+0+0±2=输入的5的值+0。这就是解法了!
用树状数组维护一个差分数组的前缀和,因为可推得若b[i]=a[i]-a[i-1],则a[i]=b[1]+…+b[i] (b[1]=a[1]-a[0],a[0]=0) 。 可发现a[i]只与b[j] (j<=i)有关,若将b[j]加上delta,其后所有值都将加dlt,因此只需改变b[i]就可实现b[i]到b[n]的区间修改。而将b[j+1]减去dlt,对a[j]无影响,其后所有值也减去dlt,恢复原值,即实现了区间修改操作。 因为求取a值用到的是前缀和,因此设t[i]为b[1]到b[i]的前缀和,a[i]=t[i]=b[1]+…b[i],即可大大降低时间复杂度。
#include<iostream>
using namespace std;
#include<cstring>
long long int n ,m;
const int N = 5000005;
int a[N],c[N];//zhuangtaishuzu
int lowbit(int x){
return x & (-x);
}
void updata(int x, int v){
for(int i = x; i <= n; i+=lowbit(i)){
c[i] += v;
}
}
int getsum (int x){
int sum = 0;
for(int i = x;i > 0; i-=lowbit(i)){
sum +=c[i];
}
return sum;
}
int main()
{
cin >> n >>m;
memset(c, 0 ,sizeof(c));
for(int i = 1; i<=n; i++) {
cin >> a[i];
updata(i,a[i] - a[i - 1]); //这里是a[i] - a[i - 1],不同于一模板;
}
int t, x, l, r, k;
for(int i = 1; i<=m; i++) {
cin >> x;
if(x == 1){
cin >>l >> r >>k;
updata(l , k); //这里是x - y区间都+k;
updata(r + 1,-k);
}
else {
int s ;
cin >> s;
cout << getsum(s)<<endl;
}
}
return 0;
}
39.对N!质因数分解
#include<iostream>
using namespace std;
int a[100010] = {0};
int n;
bool is_prime(int x){
if(x == 1||x == 0)return false;
else if(x == 2)return true;
else if(x > 2){
for(int i = 2; i * i <= x; i++) {
if(x % i == 0)return false;
}
return true;
}
}
int main()
{
cin >> n;
int w;
for(int i = 2; i<=n; i++) {
w = i;
for(int k = 1; k <=i; k++) {
while((w % k==0)&&is_prime(k)==1&&w > 1)
{
a[k]++;
w = w / k;
}
}
}
for(int i = 0; i <= n; i++) {
if(a[i]!=0)cout << i << ' '<<a[i] <<endl;
}
return 0;
}
40.均分一组数最小移动
#include<iostream>
using namespace std;
int main()
{
int n, t = 0,aver = 0, sum = 0;
cin >> n;
int a[n + 2];
for(int i = 0; i < n; i++){
cin >> a[i];
sum+= a[i];
}
aver=sum/n;
for(int i = 0; i< n; i++) {
a[i]-=aver;
}
for(int i = 0; i < n; i++) {
if(a[i] == 0)continue;
a[i + 1] += a[i];
t++;
}
cout << t <<endl;
return 0;
}
41.小A点菜搜索和背包
#include<iostream>
using namespace std;
long long int a[100000], b[10000];
//a[i] 表示第i道菜价格,b[i]表示是否选择第i道菜
int n, m,sum = 0;
void dfs(int k , int x){//k表示已选的菜的总价格,x表示选到了第i道菜
if(k > m)return;//如果价格已经超出推出
if(k == m){//价格正好
sum++;
return;//返回
}
for(int i = x + 1;i <= n ;i++) {//因为选到了第x道菜,所以从x+1道菜开始
if(b[i]==0) // 如果没选过这道菜
{
b[i] = 1; //选择这道菜
dfs(k + a[i], i); // 价格加上这道菜价格
b[i] = 0;//不选择这道菜
}
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
dfs(0, 0);
cout<<sum << endl;
return 0;
}
f[j] += f[j - a[i]];
现在的花费+=我不点这个菜的花费;
#include<iostream>
using namespace std;
int n, m;
int a[10000];
int f[100000];
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
f[0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = m; j >= a[i]; j--) {
f[j] += f[j - a[i]]; //现在的花费+=我不点这个菜的花费;
}
}
cout << f[m] <<endl;//输出最后一个点的花费
return 0;
}
42.字符串匹配
char *a=“abcde”;母串
char *b=“bc”;模式串
1.暴力
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main(){
string a;
string b;
cin >> a;
cin >> b;
int x = 0;
for(int i = 0;a[i]; i++ ) {
int flag = 1;
for(int j = 0;b[j]; j++) {
if(a[i + j] == b[j])continue;
flag = 0;
}
if(flag){cout << i;return 0; x = 1;}
}
if(x != 1)cout << -1 <<endl;
return 0;
}
2.KMP算法
KMP的关键时利用匹配失败后的信息尽量减少模式串与主串匹配次数以达到快速匹配的目的(母串指针不变模式串指针移动) 具体实现就是实现一个next数组
对比暴力算法优化首尾匹配
在求next数组时不用考虑母串 母串和模式串相匹配成功的可以将母串中的字符等效为模式串的匹配成功的位置
next数组的推导本质就是模式串的自我匹配过程
MAX[k] 1<k<j p1 = p(k-1) 等于 p(j - k + 1) - p(j - 1)
next[1] = 0;
next[j] = k && p[j] = p[k]
next[j + 1] = k + 1
3.SNMDAY算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vjCddon-1574958449332)(file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\2035756541\QQ\WinTemp\RichOle}HZ~$8OJ_N[PRUE[_F{L7}X.png)]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TEST(func, a, b) {\
printf("%s(\"%s\", \"%s\") = %d\n", #func,a, b, func(a, b));\
}
int Sunday(char *str, char *pattern) {
#define BASE 128
int ind[BASE] = {0};
int len = strlen(pattern), max_len = strlen(str);
for(int i = 0; i < BASE; i++) {
ind[i] = len + 1;
}
for(int i = 0; i < len; i++) {
ind[pattern[i]] = len - i;
}
for(int i = 0; i < max_len=n;) {
int flag = 1;
for(int j = 0; j < len; j++) {
if(str[i + j] == pattern[j]) continue;
i += ind[str[i + len]];
flag = 0;
break;
}
if(flag) return i;
}
return -1;
}
int main() {
char str[100], pattern[30];
while(scanf("%s%s", str, pattern) != EOF) {
TEST(Sunday, str, pattern);
}
return 0;
}
Sunday算法是从前往后匹配,在匹配失败时注意母串中参加匹配的最末位字符的下一位字符
1.如果该字符没有在模式串中出现则直接跳过,位移位数 = 模式串长度 + 1
2.如果出现则位移位数 = 模式串长度 - 该字符最右出现的位置(以0开始) = 模式串中该字符最右出现的位置到尾部的距离 + 1
s | u | b | s | t | r | i | n | g | s | e | a | r | c | h | i | n | g | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s | e | a | r | c | h |
第一次匹配失败在母串u的位置找母串参加匹配的下一位字符i在模式串中未出现,模式串的移动位数 = 模式串 + 1 = 6 + 1
s | u | b | s | t | r | i | n | g | s | e | a | r | c | h | i | n | g | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s | e | a | r | c | h |
第二次匹配失败在母串第一个位置找母串参加匹配的下一个字符r在模式串的位置是3移动位数 = 模式串 - 字符最右侧出现的位置 = 字符最右侧出现位置到模式串尾的距离 - 1 = 6 - 3 = 2 + 1
s | u | b | s | t | r | i | n | g | s | e | a | r | c | h | i | n | g | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s | e | a | r | c | h |
则匹配成功
另一种匹配方式:
记模式串为S,子串为T,长度分别为N,M
对于T,我们做一个简单而巧妙的预处理:记录T中每一种字符最后出现的位置,将其存入一个数组中。
假设在发生不匹配时S[i]≠T[j],1≤i≤N,1≤j≤M。设S此次第一个匹配的字符位置为L。显然,S[L+M+1]肯定要参加下一轮的匹配,并且T至少要与S[L+M+1]匹配才有可能与整个S匹配。
这时我们就寻找T中S[L+M+1]出现的位置了。利用我们预处理好的数组,可以O(1)查找出那个位置u,并将其直接移动至T[u]==S[L+M+1]。特殊地,若S[L+M+1]没有在T中出现,那么T不可能会与S[L+M+1]匹配,则将T的第一位直接移动到S[L+M+2],继续匹配。直至L+M>N时,匹配完毕。
Sunday算法思想跟BM算法很相似,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在匹配串中出现则直接跳过,即移动步长= 匹配串长度+1;否则,同BM算法一样其移动步长=匹配串中最右端的该字符到末尾的距离+1。
S:abcceabcaabcd
T:abcd
发现d与c不匹配。此时S[L+M+1]==‘e’,没有出现在T中。于是:
S:abcceabcaabcd
T:--------abcd
发现d与a不匹配。此时S[L+M+1]==‘a’,T中最后出现在T[0]。于是:
S:abcceabcaabcd
T:--------------abcd
成功匹配。
#include<iostream>
using namespace std;
#include<string>
int sunday(string str,string pattern){
#define base 128
int ind[base] = {0};
int len = pattern.length();
int max_len = str.length();
for(int i = 0; i < base; i++) {
ind[i] = len + 1;
}
for(int i = 0; i < len; i++) {
ind[pattern[i]] = len - i;
}
for(int i = 0; i<max_len;){
int flag = 1;
for(int j = 0; j < len ; j++) {
if(str[i+j]==pattern[j])continue;
i+=ind[str[i + len]];
flag = 0;
break;
}
if(flag)return i;
}
return -1;
}
int main()
{
string a, b;
cin >> a >> b;
cout << sunday(a, b) <<endl;
return 0;
}
43.各种判断函数
1.判断是否是字母
isalpha(),若是返回true,否则返回false
2.判断是否是数字
isdigit(),若是返回true,否则返回false
3.判断是否是大写字母
isupper(), 若是返回true,否则返回false;
4.判断是否是小写字母
islower(),若是返回true,否则返回false;
5.大写转化为小写字母
tolower()
6.小写转化为大写字母
toupper()
44.文件输入输出
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
45.“1234567891011121314…” 输入N ,s += to_string(i);
#include<bits/stdc++.h>
using namespace std;
string s;//答案
int n,a;
int main()
{
.scanf("%d",&n);
for(int i=1;i<=n;i++)s+=to_string(i);//string+string之将第二个string加到第一个后面
//因为1,2,...10,11...的位数必定大于1,所以累加n次一定不会炸
putchar(s[--n]);//string是从0开始储存的,所以要--n
return 0
}
using namespace std;
#include<cstring>
int main()
{
int n;
cin >> n;
string a;
for(int i = 1; i <= n ;i++){
a += to_string(i);
}
for(int i = 0; i < a.length(); i++){
cout << a[i] ;
}
return 0;
}
##46.数字反转算法
int reverse(int x){
int max = 0x7fffffff,min = 0x80000000;
long temp = 0;
while(x!=0){
temp = temp*10 + x % 10;
x/=10;
}
if(temp > max||temp<min){
return 0;
}
else {
return (int)temp;
}
}
47.map构建hash
map<int,int>hash
map<string,int>hash
查找大于n/2个的字符串
#include<iostream>
using namespace std;
#include<map>
#include<cstring>
int main()
{
map<string,int>hash;
int n;
string res;
cin >> n;
string a;
for(int i = 1; i <= n;i++){
cin >> a;
hash[a]++;
if(hash[a]>n/2){
res = a;
}
}
cout << res <<endl;
return 0;
}
48.求只出现一次的数字
class Solution {//除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
public:
int singleNumber(vector<int>& nums) {
int res = nums[0];
for(int i = 1; i < nums.size(); i++){
res = res ^ nums[i];
}
return res;
}
};
49.开辟动态数组空间int *dp= new int[n+1];
50.string中的replace替换
#include <iostream>
using namespace std;
#include <cstring>
#include <algorithm>
int main()
{
int n;
scanf("%d", &n);
string s;
size_t pos;
string a = "Ban_smoking";
string b = "No_smoking";
for(int i = 0; i < n; i ++) {
cin >> s;
pos = s.find(a);
while(pos != s.npos) {
s.replace(pos, a.length(), b);
pos = s.find(a);
}
cout << s << endl;
}
return 0;
}
51.二分法求近似值
#include <cstdio>
#include <cmath>
#define EPSILON 1e-7
double bisection(int p, int q, double (*func)(int, int, double));
double f(int p, int q, double x);
int main() {
int p;
int q;
scanf("%d %d", &p, &q);
printf("%.4lf\n", bisection(p, q, f));
return 0;
}
double bisection(int p, int q, double (*func)(int, int, double)) {
double a = -20.0, b = 20.0;
double m;
while(1) {
m = (a + b) / 2;
if(fabs(func(p, q, m)) < EPSILON) {break;}
if(func(p, q, m)*func(p,q, a) < 0) {
b = m;
} else if(func(p, q, m) * func(p, q, b) < 0) {
a = m;
}
}
return m;
}
double f(int p, int q, double x) {
return p * x + q;
}
52. “.”和“-> ”的区别
(*结构体指针名).结构体成员元素名
结构体指针名 -> 结构体成员元素名
53、排序去重
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int a[15];
int n;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
n = unique(a, a + n) - a;
for(int i = 0; i < n; i++) {
cout << a[i] << ' ';
}
return 0;
}
000.小知识
-
首先是“const double pi = acos(-1.0);”。这里也声
明了一个叫pi的“符号”,但是const关键字表明它的值是不可以改变的——pi是一个真正的数
学常数(3)。 -
#include<iostream> using namespace std; #include<algorithm> int main() { int a[5] = {2, 4, 6, 8 ,10}; int w = std::lower_bound(a, a + 5, 8) - a; // 查找第一个大于等于的值 cout << a[w] << endl; int s = std::upper_bound(a, a + 5, 8) - a; // 查找第一个大于的值 cout << a[s] << endl; return 0; }