CSP语法题基础(二)

CSP算法题基础(2)

计算100立方和。立方和公式是平方和公式的平方 k次方公式是k-1次方公式的递推

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
    
    int i=1,sum = 0;
    while(i <= 100){
        sum = sum +i*i*i;
        i++;
    }
    cout<<sum<<endl;
    
    
    
    return 0;
}

求斐波那锲数列的第n项:

\[数列初值:f(1)=1,f(2)=1 \]

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
    int a = 1,b = 1;
    int temp;
    int num ;
    cin >> num;
    
    int i=1;
    while( i <= num-1 ){			//注意第一项
        temp = a + b;
        a = b;
        b = temp;
        i++;
    }
    cout<<a<<endl<<b<<endl;
    
}

do while用的比较少,可能只占5%;而while可以占到95%。功能上来说完全等价。“先上车后买票的思想”

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
    
    int s = 0,r = 0;
    
    int i=1,j=1;
    while(i<=10){
        s = s+i;
        i++;
    }
    cout<<s<<endl;
    do{
        r = r+j;
        j++;
        
    }while(j <=10)
    cout<<r<<endl;
    return 0;
}

break是直接跳过该循环,并且是全部跳过;

continue是只跳过其中一次循环,继续执行剩下的其他循环

而且二者跳出循环的位置也略有不同:

判断一个数是不是质数。

//对于一个数n,判断2 to n-1里面有没有n的因子
#include<iostream>
#include<cstdio>

using namespace std;

int main(){
    
    int n;
    cin >> n;
    
    bool is_prime = true;
    
    for(int i = 2;i <= n-1;i++){
        if(n%i == 0){
            is_prime = false;
            break;//break是从for循环里面跳出来
        }
    }
    
    if(is_prime){
        cout<<"是质数"<<endl;
    }else{
        cout<<"不是质数"<<endl;
    }
    
    
    return 0;
}

计算100以内的偶数

#include<iostream>
#include<cstdio>

using namespace std;

int main() {
	
	int sum = 0;
	for(int i=1;i<=100;i++)
	{
		if(i%2!=1){
			sum = sum + i;
		}else{
			continue;
		}		
	}
	cout<<"偶数和是:"<<sum<<endl; 
	return 0;
	
}

\(n*n\)矩阵输出

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
	
	// i,j控制在那个位置输出,k负责输出几?
	int n;
	cin >> n;
	
	int k=1;
	for(int i = 1;i<=n;i++){
		
		for(int j = 1;j<=n;j++){
			printf("%-3d",k); 			//-3意味着后面补上空格
			k++;
		}
		cout<<endl;
	} 
	
	return 0;
}

输出1-100以内的质数

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
	
	//经典两层循环例子 
	for(int i=2;i<=100;i++){
		bool is_prime = true;
		for(int j =2;j<i;j++){
			if(i%j==0){
				is_prime = false;
				break;				//判断是否是质数,能够整除的话,跳出本次循环进入输出阶段 
			}
				//break;
		}
		if(is_prime){				//输出阶段,判断是否是质数,是质数就打印输出 
			cout<<i<<endl;
		}
	} 
	
	return 0;
}

每一个文件都会有一个文件结束符,但是我们的前端是不会显示的,后端才会有说明EOF或者是-1。cin函数在读入字符的时候会有返回值1,当读到EOF(有的是-1)的时候返回值会是0,所以在acwing721中读到末尾0的时候停止计数,除了可以使用while+if判断结构,还可以直接使用while(cin>>n),无需判断结构。

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
    
    int n;
    //不知道输入多少个数,用while循环比较好
    while(cin >> n){
        
        
        if(n == 0){
            break;
        }               //输入未知个数 的数,直到是0才停下来
        
        for(int i = 1;i<=n;i++){
            cout << i << " ";
        }
        cout << endl;
    }
    
    
    return 0;
    
}

类似地,scanf读到EOF返回值是-1,可以有:

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
    
    int n;
    //不知道输入多少个数,用while循环比较好
    while(scanf("%d",&n) != -1){
        
        
        if(n == 0){
            break;
        }               //输入未知个数 的数,直到是0才停下来
        
        for(int i = 1;i<=n;i++){
            cout << i << " ";
        }
        cout << endl;
    }
    
    
    return 0;
    
}

10000以内的输入变量cin和scanf效率差不多,但是要是超过10000个输入变量scanf的效率会高很多。

数组

#include<iostream>

using namespace std;

int main(){
    int a[3]={1,2,3};
    int b[]={4,5,6};
    int c[5] = {1,2,3};  //这种情况下,会默认没有定义的变量是0
    
    int d[10] = {0};  	//将数组全部初始化成0
    return 0;
}

函数里面定义数组的时候,往往是定义到栈空间里;栈空间往往只有1MB,因此定义比较大的数组的时候可能会爆掉;

解决方法:定义到函数外面,因为函数外面定义数组是定义到 堆中,堆空间比较大

同样的一个数组定义到函数(比如main函数)外面,即使不用初始化,会默认是0,从这里看得出定义位置不同,数组会有不同变化。

也就是讲,定义到函数外面的数组甚至不用初始化成0。

局部变量的值是随机的,需要初始化;全局变量的值不需要初始化,默认是0

数组方法求斐波那契数列第n项:

#include<iostream>

using namespace std;

int main(){
    
    int a[100];
    
    int n;
    cin >> n;
    
    a[0]=0;
    a[1]=1;
    
    for(int i=2;i<=n;i++){
        a[i] = a[i-1]+a[i-2];
    }
    cout<<a[n]<<endl;
    
    return 0;
}

输入数,然后倒叙输出:

#include<iostream>

using namespace std;

int main(){
    
    int a[100];
    
    int n;
    cin >> n;
    
    
    for(int i=0;i<n;i++){
      	cin >> a[i];  
    }
    
    for(int j=n-1;j>=0;j--){
        cout << a[j]<< " ";
    }
    
    return 0;
} 

输入n个数,翻转k次:

//使用翻转函数法
include<iostream>
include<algorithm>
    
using namespace std;

int main(){
    
    int a[100];
    
    int n,k;
    cin >> n>>k;
    
    for(int i =0;i<n;i++){
        cin >> a[i];
    }
    
    reverse(a[0],a[n]);
    reverse(a[0],a[k]);
    reverse(a[k],a[n]);
    
    for(int j=0;j<n;j++)
        cout<<a[i]<" ";
    return 0;
}

高精度运算(平时运算属于低精度运算,有效位数比较少)

高精度2的n次幂

数组初始化方式memset函数(在库里)

#include<iostream>
#include<cstdio>
using namespace std;

int main(){
    
    int a[10],b[10],c[10];
    //使用memset进行初始化,需要注意不是对每一个int初始化,而是对每一个Byte进行初始化
    memset(a,0,40);		//第一个参数是数组名,第二个参数是需要初始化的内容,第三个参数是从开头到需要初始化的位置,单位是字节
    
  	for(int i=0;i<10;i++){
    	b[i] = i;
	}
	
	memcpy(c,b,sizeof c);	  	//把b数组复制到c数组上
    
    
    memset(a,0,sizeof a)//这里的40也不需要手算,可以用sizeof,这里的sizeof不是函数,而是运算符
    for(int i=0;i<10;i++)
        cout<<a[i]<<" ";
    
    return 0;
}

字符串之字符数组

#include<iostream>
#include<string.h>
using namespace std;

int main(){
    //字符串通常是使用字符数组来进行存储,区别是末尾有'\0'的就是字符串;末尾没有'\0'的是普通的字符数组
    char a[]={'c','+','+'};	//就是字符数组
    char b[]={'c','+','+','\0'}; //就是字符串
    char c[]="c++"; //就是字符串    a字符数组是3个字符;b字符数组是4个字符数组;c字符数组是4个字符数组
    
    //字符串从某一特定字符开始输出,可以使用a+k的格式
    cout << b+1 << endl; 	//就是从+开始输出
    printf("%s",c+1);
    
    //输入字符串也可以不从0号元素开始输入
    char ss[200];
    
    cin >> ss+1;
    cout << ss+1<<endl<<ss[1]<<endl;
    //scanf和printf也有类似效果
    scanf("%s",ss+1);
    printf("%s",ss+1);
    
    //输入输出都是遇到空格、回车、文件结束符才停止
    
    
    
    //要想把一行全部读入(包括空格)把包括空格读进来,需要使用fgets(字符数组,最多读入多少字符,stdin) 【把标准读入当做文件】  和getline(),   gets()已经被淘汰了
    //fgets是把输入读入到字符数组,getline是把输入读入到string里
    char ss[200];
    /*
    cin >> ss+1;
    cout << ss+1<<endl<<[ss];
	*/
	
   	//	fgets和getline不能隔离空格和回车,会把按下的回车键也读入到字符数组
	fgets(ss,100,stdin);
	cout<<ss<<endl;
	
	string s;
	getline(cin,s);
	
	cout<<s<<endl;
    // 输出一个字符串,还可以使用更简单的puts()函数,自带空格	
    
    这三个函数都在#include<string.h>里
    //求字符串的长度 
	strlen(s);
	//按照字典序比较字符串的大小,如果是a小于b的话返回-1,如果是a=b的话返回0;如果是a>b的话返回1 
	strcmp(a,b);
	// 将字符串复制给a开始的字符数组
	strcpy(a,b); 
    
    return 0;
}

刷新缓存(终端特性,终端本身也是函数):其实就是把控制台的输入传输到程序中去,键盘里的输入其实就是,输入字符到键盘缓存,按下回车之后,缓存中的数据就会进入程序之中

字符串之string

可变长字符序列;比字符数组更好用;需要使用库#include

#include<iostream>
#include<string>
#include<cstdio>

using namespace std;

int main(){
    
    //定义方式
    string s1;	//定义空字符串
    string s2 = s1; //不需要strcpy,直接可以赋值过来
    string s3 = "ni hao";//s3是该字符串字面值的一个副本
    string s4(10,'c');	//定义10个c,内容是:cccccccccc
    
    //读入方式
    string s1,s2;
    cin >> s1 >> s2;
    cout << s1 << " "<< s2<< endl;
    // //c++98 不支持这种写法,c++11支持
    string s = "Hello World!";
	
	for(char c:s) 	cout<<c<<endl; 
    //  若想通过改变c的值来改变s的每一个值,可以在c的前面添加&  					for(char &c:s)	c = 'a';
    //	添加一个引用符号,后面在改变c的时候,s也会自动跟着变化
    //	引用符号其实起着一个绑定的作用
    
    //	auto类型,编译器靠着上下文来 猜 类型,有时候会猜错,c++中有的类型非常长,使用auto会非常长
    
    return 0;
}

字符串流stringstream

stringstream在头文件#include里面;通常我们使用stringstream将字符串变成字符串流

stringstream ssin(s)			//将字符串变成字符串流 的语法。ssin和字符串里面的cin非常相似,不同点是ssin是将字符串流里的读入

用处是可以将字符串变成字符串流,然后从字符串流中提取我们需要的各种信息

比如字符串中 123 yxc 321 1.123就能分别提取出int、string、int、double类型,需要什么信息读取到什么变量中 去

int main(){
    string s;
    getline(cin,s);
    
    //将字符串初始化成 字符串流
    stringstream ssin(s);
    int a,b;
    string str;
    double s;
    
    ssin >> a >> str >> b >> s ;//最好用空格隔开 
    cout << a << endl << str << endl << b << endl << s << endl;
    
    return 0;
}

给空字符串里面添加字符,可以直接使用 + 符号,

string s;
s = s+'a';//s里面是a
s = s+'b';//s里面是ab
s = s+'c';//s里面是abc

s.pop_back();

PS:Windows下的回车使用的是\r\n(1310),而我们Linux下使用的回车一般是\n(10)

​ fgets()会把回车读进来,最后一定会补上一个回车

string s;
s.substr(pos,len)//返回的是一个子字符串,位置是pos,长度是len
//要是没有len参数,则默认的是从pos到字符串末尾

要想输出程序运行时间,可以使用#include

这个库中的clock()函数可以返回当前时刻

#include<cmath>

int start_time = clock();


cout << clock - start_time << endl;// 单位是ms

第一种双指针算法

//模式如下
// 最外层一层循环
for(int i =0;i<s.size();i++){
    int j =i;	//从当前位置开始
    while(j<s.size() && s[j] == s[i]) j++;	//跳出循环时j已经在不连续相等的第一个字符
    i = j-1;	//由于最外层循环有i++,所以必须减一,否则会下一轮的起始i会从连续相等的第二个字符开始
}

posted @ 2021-03-10 22:53  _Sandman  阅读(154)  评论(0编辑  收藏  举报