2020.8.21-2020.9.6 the first version

1 闰年

(year % 4 == 0 && year % 100 != 0) || (year % 400 = 0)
预处理每个月的天数,用空间换时间
int daytab[2][13]={
    {0,31,28,31,30,31,30,31,31,30,31,30,31}
    {0,31,29,31,30,31,30,31,31,30,31,30,31}
}

2 保留几位输出

cout<<fixed<<setprecision(2);

3.C语言读取text文件

#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
	
	//逐行写 
	FILE *fp = NULL;
    char buffw[26];
    
	fp = fopen("1.txt", "w+");
	for(int i=0;i<26;i++){
		buffw[i]='a'+i;
	} 
	//fprintf(fp, "This is testing for fprintf...\n");
	fputs(buffw,fp);
    fclose(fp);	 
    
    //逐行读 
	//FILE *fp=NULL;
	char buffr[255];
	fp = fopen("D:\\devcpp\\baoyan\\1.txt", "r");
	while(!feof(fp)){
		fgets(buffr,255,fp);
//	printf("%s\n", buff); 
    	cout<<buffr;
	}
	fclose(fp);
}


只读模式创建文件
fp.open("2.txt",fstream::out);

c++读取文件首选

#include<iostream>
#include<fstream>
#include<stdio.h>
using namespace std;
int main(){	
	//写入 
	fstream wfile;
	wfile.open("1.txt");
	char sdata[26];
	for(int i=0;i<26;i++){
		sdata[i]='z'-i;
		wfile << sdata[i]<<endl;
	}
	//cout<<sdata<<endl;
	wfile.close();
	

	//读取 
	string data="";
	fstream rfile;
	rfile.open("1.txt");
	//rfile.getline(data,27);//读取num-1个字符 
	while (getline(rfile,data))
	cout << data << endl;
	rfile.close();
	return 0;
	
} 

4.vector容器

//vector容器
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
	vector<int>obj;
	vector<int>::iterator it;
	for(int i=5;i>=0;i--){
		obj.push_back(i);
	}
	//sort(obj.begin(),obj.end());
	for(it=obj.begin();it!=obj.end();it++){
		cout<<*it<<" ";
	}
	
	return 0;
}

5 sort函数

sort(first,last,comp)
起始地址first,last
comp 排序方式默认升序
重写sort函数可以变为降序
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
bool compare(int a,int b) { 
	return a>b; //升序排列,如果改为return a>b,则为降序 
}
int main(){
	int n=5;
	int arr[n];
	for(int i = 0; i < n; i++){
		scanf("%d",&arr[i]);
	}
	sort(arr,arr+n,compare);
	for(int i = 0; i < n; i++){
		printf("%d ",arr[i]);
	}
	return 0;
}
compare函数:
比较函数,在遇到新的排序规则时,黄金法则:当比较函数返回值为true时,表示比较函数是第一个参会将排在第二个参数前面。
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct student{
    string name;
    int grade;
    int order;
};
bool compare1(student a,student b){
    if(a.grade==b.grade){
        return a.order<b.order;
    }
    else{
        return a.grade>b.grade;
    }
}
bool compare2(student a,student b){
    if(a.grade==b.grade){
        return a.order<b.order;
    }
    else{
        return a.grade<b.grade;
    }
}
int main(){
    int n;
    int func;
    cin>>n>>func;
    student stu[n];
    for(int i=0;i<n;i++){
        cin>>stu[i].name>>stu[i].grade;
        stu[i].order=i;
    }
    if(func==0){
        sort(stu,stu+n,compare1);
    }else{
        sort(stu,stu+n,compare2);
    }
    for(int i=0;i<n;i++){
        cout<<stu[i].name<<" "<<stu[i].grade<<endl;
    }
    return 0;
}

6.二分查找

在查找次数很多的情况下,二分查找优于线性查找
二分查找需要先排序,再查找;
while(left<=right){
注意二分法退出循环的条件。
#include<iostream>
#include<algorithm>
using namespace std;
int BinarySearch(int a,int num[],int n){
    int left=0;
    int right=n-1;
    int mid=(left+right)/2;
    while(left<=right){
        if(num[mid]==a){
            return 1;
        }
        else if(num[mid]<a){
            left=mid+1;
        }else{
            right=mid-1;
        }
        mid=(left+right)/2;
    }
    return 0;
}
int main(){
    int n,m;
    while(cin>>n){
        int arr[n];
        for(int i=0;i<n;i++){
            cin>>arr[i];
        }
        sort(arr,arr+n);
        cin>>m;
        int num,target;
        for(int i=0;i<m;i++){
            cin>>num;
            target=BinarySearch(num,arr,n);
            if(target==1){
                cout<<"YES"<<endl;
            }else{
                cout<<"NO"<<endl;
            }
        }
    }
    return 0;
}

7.字符串string

string

插入删除

长度
#include<iostream>
#include<string>
using namespace std;
int main(){
    string str="Hello World!";
    int n=str.length();//长度
    str.insert(0, "zq");//把"zq"插入到位置"0" 
    //cout<<str;
    str.erase(0,2);//删除从位置0开始的2个字符 
    str.clear();
	cout<<str; 
    
    return 0;
}

常用函数

find()
没找到返回-1
substr()
下标从0开始
#include<iostream>
#include<string>
using namespace std;
int main(){
    string str="Hello World!";
    int found=str.find("Hello");
	cout<<found<<endl; 
    string str1=str.substr(0,5);
    cout<<str1;
    return 0;
}


常见应用

  • 字符串处理

巧用ASCII码计算
#include<iostream>
#include<string>
using namespace std;
int main(){
    string str1,str2;
    cin>>str1>>str2;
    int len1,len2;
    len1=str1.length();
    len2=str2.length();
    int sum=0;
    for(int i=0;i<len1;i++){
        for(int j=0;j<len2;j++){
            sum=sum+(str1[i]-'0')*(str2[j]-'0');
        }
    }
    cout<<sum;
    return 0;
}

  • getline()可以获取一行带空格的字符串,cin>>str遇到空格就会停止输入

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    
    string str;
    int sym;
    while(getline(cin,str)){
        for(int i=0;i<str.length();i++){
            if(str[i]<='z'&&str[i]>='a'){
                sym=str[i]-'a';
                sym=(sym+1)%26;
                str[i]='a'+sym;
            }
            if(str[i]<='Z'&&str[i]>='A'){
                sym=str[i]-'A';
                sym=(sym+1)%26;
                str[i]='A'+sym;
            }
        }
        for(int i=0;i<str.length();i++){
            cout<<str[i];
        }
        cout<<endl;
    }
    
    return 0;
}

  • 循环平移

取余的方法P49

  • 字母出现次数统计

用一个number数组统计各个出现的概率
学会构造辅助数组
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int num[128];//128个ASCII码
int main(){
    string str1,str2;
    while(getline(cin,str1)){
        if(str1 == "#"){
            break;
        }
        getline(cin,str2);
        memset(num,0,sizeof(num));
        for(int i=0;i<str2.size();i++){
            num[str2[i]]++;
        }
        for(int i=0;i<str1.size();i++){
            printf("%c %d\n",str1[i],num[str1[i]]);
        }
    }
    
    return 0;
}

  • int的范围

int有32位,2^32-1,注意int的范围使用
注意pow函数,需要头文件<math.h>,pow(2,n);
#include<iostream>
#include<string>
#include<algorithm>
#include<math.h>
using namespace std;
int main(){
    string s;
    while(cin>>s){
        int sum=0;
        for(int i=0;i<s.length();i++){
            if(s[i]=='0')continue;
            sum=sum+(s[i]-'0')*(pow(2,s.length()-i)-1);
        }
        cout<<sum<<endl;
    }
}

  • 首字母大写问题

复习:注意getline函数的使用(C语言可以用gets)
大写与小写字母的ASCII差值的使用
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    string s;
    int p;
    while(getline(cin,s)){
        if(s[0]>='a'&&s[0]<='z'){
            p=s[0]+'A'-'a';
            s[0]=p;
        }
        for(int i=1;i<s.size();i++){
            if(s[i]==' '||s[i]=='\t'||s[i]=='\n'||s[i]=='\r'){
                i=i+1;
                if(s[i]>='a'&&s[i]<='z'){
                    p=s[i]+'A'-'a';
                    s[i]=p;
                }
                else{
                    i=i-1;
                }
            }
        }
        cout<<s;
    }
}


字符串匹配

kmp算法

重点理解next数组的求法
#include<iostream>
#include<string>
#include<algorithm>
//KMP算法 
using namespace std;
const int MAXM=10000;
const int MAXN=1000000;

int nextTable[MAXM];
int pattern[MAXM];
int text[MAXN];

//创建next表
void GetNextTable(int m){
	int j=0;
	nextTable[j]=-1;
	int i=-1;
	while(j<m){
		if(i==-1||pattern[i]==pattern[j]){
			i++;
			j++;
			nextTable[j]=i;
		}else{
			i=nextTable[i];
		}
	}
} 
int main(){
	
	
	
	return 0;
} 

8 数据结构一

向量

vector

主要应用于不知道需要多大数组的方法

#include<vector>
push_back()
pop_back()
empty()
size()
insert()
erase()
clear()
begin()
end()

#include<iostream>
#include<string>
#include<vector>
using namespace std;

vector<int>obj;

int main(){
	
	for(int i=0;i<5;i++){
		obj.push_back(i);
	}
	obj.insert(obj.begin(),3,15);
	obj.pop_back();
	for(int i=0;i<obj.size();i++){
		cout<<obj[i]<<endl;
	}
	obj.erase(obj.begin()+5,obj.end());
	vector<int>::iterator it;
	for(it=obj.begin();it!=obj.end();it++){
		cout<<*it<<" ";
	}
	obj.clear();
	
	return 0;
}
https://www.nowcoder.com/practice/ccc3d1e78014486fb7eed3c50e05c99d?tpId=60&tqId=29492&tPage=1&ru=/kaoyan/retest/1001&qru=/ta/tsing-kaoyan/question-ranking
求因数
#include<iostream>
#include<vector>
using namespace std;

int s(int x){
    int sum=0;
    for(int i=1;i<=x/2;i++){
    	if(x%i==0){
    		sum=sum+i;
		}
	}
    //cout<<sum<<endl; 
    return sum;
}
int main(){
    vector<int>obj1;
    vector<int>obj2;
    for(int i=2;i<=60;i++){
        if(i==s(i)){
            obj1.push_back(i);
        }else if(i<s(i)){
            obj2.push_back(i);
        }
    }
    cout<<"E"<<":";
    for(int i=0;i<obj1.size();i++){
        cout<<" "<<obj1[i];
    }
    cout<<endl;
    cout<<"G"<<":";
    for(int i=0;i<obj2.size();i++){
        cout<<" "<<obj2[i];
    }
    return 0;
}


队列

STL-queue

#include<queue>
queue<type>name
empty()
size()
push()
pop()
front()
back()
队头删除元素
队尾添加元素

队列应用约瑟夫问题

循环队列

案例

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
//模拟循环队列 
int main(){
	int n,p,m;
	while(cin>>n>>p>>m){
		if(n==0&&p==0&&m==0){
			break;
		}
		queue<int>children;
		for(int i=1;i<=n;i++){
			children.push(i);//加入编号 
		}
		for(int i=1;i<p;i++){
			children.push(children.front());
			children.pop();//把编号为p的放在第一位 
		}
		while(!children.empty()){
			for(int i=1;i<m;i++){//m-1个小孩重新入队 
				children.push(children.front());
				children.pop();
			}
			if(children.size()==1){
				cout<<children.front()<<endl;
			}else{
				cout<<children.front()<<',';
			}
			children.pop();
		} 
	} 
	
	return 0;
}

stack
stack<typename>name
empty()
size()
push()
pop()
top()和队列不同的地方,只能访问栈顶

栈的应用

无法实现确定存放容器的大小

逆序输出

注意:int最大值:2^31-1=214748364(9位)
long long 最大值 2^64-1=9223372036854775807(19位)
#include<iostream>
#include<string>
#include<algorithm>
#include<stack>
using namespace std;

stack<long long>st;//用long long
int main(){
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            long long num;
            cin>>num;
            st.push(num);
        }
        while(!st.empty()){
            cout<<st.top()<<" ";
            st.pop();
        }
        cout<<endl;
    }
    
    
    
    return 0;
}


括号匹配

括号左右匹配

表达式求值

简单计算器
用栈解决
数据栈
符号栈
#include<iostream>
#include<algorithm>
#include<stack>
#include<string>
#include<iomanip>
using namespace std;

int pr(char c){//优先级顺序 
	if(c=='#'){
		return 0;
	}else if(c=='$'){
		return 1;
	}else if(c=='+'||c=='-'){
		return 2;
	}else{
		return 3;
	}
} 
//取参与运算的数据 
double getNumber(string s,int &index){
	double number=0;
	while(s[index]>='0'&&s[index]<='9'){
		number=number*10+s[index]-'0';
		index++;
	}
	return number;
	cout<<1;
	cout<<number<<endl; 
}
//计算
double Calculate(double x,double y,char op){
	double result=0;
	if(op=='+'){
		result=x+y;
	}else if(op=='-'){
		result=x-y;
	}else if(op=='*'){
		result=x*y;
	}else if(op=='/'){
		result=x/y;
	}
	return result;
} 
int main(){
	string str;
	while(getline(cin,str)){
		if(str=="0"){
			break;
		}
		int index=0;//字符串处理定位
		stack<double>data;//数据栈
		stack<char>op;//运算符栈
		str=str+'$';
		op.push('#');
		//cout<<str; 
		while(index<str.size()){
			if(str[index]==' '){
				index++;
			}else if(str[index]>='0'&&str[index]<='9'){
				data.push(getNumber(str,index));
				//cout<<str; 
				//cout<<data.top();
				//cout<<"zq";
			}else{
				if(pr(op.top())<pr(str[index])){
					op.push(str[index]);
					index++;
					//cout<<str; 
				}else{
					double y=data.top();//x和y顺序不能反 
					data.pop();
					double x=data.top();
					data.pop();
					//cout<<str; 
					data.push(Calculate(x,y,op.top()));
					op.pop();
					//cout<<str; 
				}
			}
		} 
		//cout<<op.top(); 
		cout<<fixed<<setprecision(2)<<data.top()<<endl;
	}
	
	return 0;
} 

#include<iostream>
#include<stack>
#include<string>
#include<iomanip>
using namespace std;

stack<double>num;
stack<char>op;
//优先级
int pr(char s){
	if(s=='#'){
		return 0;
	} 
	else if(s=='$'){
		return 1;
	}
	else if(s=='+'||s=='-'){
		return 2;
	}
	else{
		return 3;
	}
} 
double result(double n1,double n2,char t){
	if(t=='+'){
		return n1+n2;
	}else if(t=='-'){
		return n1-n2;
	}else if(t=='*'){
		return n1*n2;
	}else if(t=='/') {
		return n1/n2;
	}
}
int main(){
	string str;
	while(getline(cin,str)){
		if(str=="0"){
			break;
		}else{
			int i=0;
			op.push('#');
			str=str+'$';
			int len=str.length();
			while(i<len){
				if(str[i]==' '){
					i++;
					//cout<<i<<endl;
				}
				else if(str[i]>='0'&&str[i]<='9'){
					int sum=0;
					while(str[i]>='0'&&str[i]<='9'){
						sum=sum*10+str[i]-'0';
						i++;
					}
					num.push(sum);
					//cout<<num.top()<<endl;
				}else{
					//cout<<str[i]<<endl;
					if(pr(op.top())<pr(str[i])){
						//cout<<str[i]<<endl;
						op.push(str[i]);
						//cout<<op.top()<<endl;
						i++;
					}else{
						double t1=num.top();
						num.pop();
						double t2=num.top();
						num.pop();
						char t=op.top();
						op.pop();
						double d=result(t2,t1,t);
						num.push(d);
					}
				}
			}
		}
		cout<<fixed<<setprecision(2)<<num.top()<<endl;
		num.pop();

	}
}


9 数学问题

进制转换

字符串的加减乘除
//author:Q_Zhang
#include<iostream>
#include<string>
#include<vector>
using namespace std;
string Divide(string str,int x){//字符串除法
    int remainder=0;   //余数 
    for(int i=0;i<str.size();i++){
        int num=remainder*10+str[i]-'0';//每一步余数与下一位的组合
        str[i]=num/x+'0';//除法运算
        remainder=num%x;//在这一位的余数
    }
    int pos=0;
    cout<<remainder<<endl;
    while(str[pos]=='0'){//去除产生多余的0
    	pos++;
	}
	return str.substr(pos);
}
int main(){
    string x;
    cin>>x;
    x=Divide(x,5); 
    cout<<x;
    return 0;
    
}

最大公约数,最小公倍数

辗转相除法求最大公约数
两数乘积除以最大公约数即为最小公倍数

非递归
#include<iostream>
using namespace std;

int max(int a,int b){
    int r;
    if(a<b){
        r=a;
        a=b;
        b=r;
    }
    r=a%b;
    while(r!=0){
        a=b;
        b=r;
        r=a%b;
    }
    return b;
}
int main(){
    int m,n,result;
    while(cin>>m>>n){
        result=max(m,n);
        cout<<result<<endl;
    }
    
    return 0;
}
递归很简单自行查阅

质数

素数筛法

找到一个素数,就将它所有倍数均标记为非素数,则判定其为素数,并标记它的所有倍数为非素数,然后继续遍历
#include<iostream>
#include<vector>
using namespace std;

const int MAXN=10001;
vector<int>prime;
bool isPrime[MAXN];

void Init(){
    for(int i=0;i<MAXN;i++){
        isPrime[i]=true;
    }
    isPrime[0]=false;
    isPrime[1]=false;
    for(int i=2;i<MAXN;i++){
        if(!isPrime[i]){
            continue;
        }
        prime.push_back(i);
        for(int j=i*i;j<MAXN;j=j+i){
            isPrime[j]=false;
        }
    }
}

int main(){
    Init();
    int n;
    bool output=false;
    while(cin>>n){
        for(int i=0;i<prime.size();i++){
            if(prime[i]>=n){
                break;
            }
            else if(prime[i]%10==1){
                output=true;
                cout<<prime[i]<<" ";
            }
        }
        if(!output){
            cout<<-1;
        }
        cout<<endl;
    }
    
    return 0;
}

质数判断

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

bool Judge(int x){
    if(x<2){
        return false;
    }
    int bound=sqrt(x);
    for(int i=2;i<=bound;i++){
        if(x%i==0){
            return false;
        }
    }
    return true;
}
int main(){
    int n;
    bool s;
    while(cin>>n){
        s=Judge(n);
        if(s){
            cout<<"yes"<<endl;
        }else{
            cout<<"no"<<endl;
        }
    } 
    return 0;
}

分解质因数

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        int num=0;
        int bound=sqrt(n);
        for(int i=2;i<=bound;i++){
            while(n%i==0){
                num++;
                n=n/i;
            }
        }
        if(n!=1)num++;//特别注意:如果n为质数的情况下
        cout<<num<<endl;
    }
    return 0;
}

快速幂

核心思想:将指数化为2进制数,1对应的位是快速求幂的分解的指数

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

int Fast(int a,int b,int mod){
	int answer=1;
	while(b!=0){ //核心思想:转化为2进制 
		if(b%2==1){
			answer=answer*a;
			answer=answer%mod;
		} 
		b=b/2;
		a=a*a;
		a=a%mod;
		
	}
	return answer;
}
int main(){
	int a,b;
	while(cin>>a>>b){
		if(a==0&&b==0){
			break;
		}
		cout<<Fast(a,b,1000)<<endl;
	}
	return 0;
} 

矩阵快速幂
原理同快速幂,初始状态为单位矩阵

大整数的加减乘除 重要

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
void Switch(string &a,string &b){
    string c=a;
    a=b;
    b=c;
}

int main(){
    string a,b;
    int len1,len2,p;
    while(cin>>a>>b){
    	vector<int>obj;
        len1=a.size();
        len2=b.size();
        if(len2<len1){
            Switch(a, b);
        }
        int remain=0;
        int i=a.size()-1;//特别注意:交换过后需要重新求解长度
        int j=b.size()-1;
        for(;i>=0;i--,j--){
            p=a[i]-'0'+b[j]-'0'+remain;
            if(p>=10){
                remain=1;
                p=p-10;
                obj.push_back(p);
            }else{
                obj.push_back(p);
                remain=0;
            }
        }
        for(;j>=0;j--){
        	p=b[j]-'0'+remain;
        	if(p>=10){
                remain=1;
                p=p-10;
                obj.push_back(p);
            }else{
                obj.push_back(p);
                remain=0;
            }
		}
		if(remain==1){
			obj.push_back(1);
		}
		for(int k=obj.size()-1;k>=0;k--){
			cout<<obj[k];
		}
		obj.clear();
		cout<<endl;
    }
    
    return 0;
}
第二种思路:进位统一处理
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
void Switch(string &a,string &b){
    string c=a;
    a=b;
    b=c;
}

int main(){
    string a,b;
    int len1,len2,p;
    while(cin>>a>>b){
    	vector<int>obj;
        len1=a.size();
        len2=b.size();
        if(len2<len1){
            Switch(a, b);
        }
        int remain=0;
        int i=a.size()-1;
        int j=b.size()-1;
        for(;i>=0;i--,j--){
            p=a[i]-'0'+b[j]-'0'+remain;
            if(p>=10){
                remain=1;
                p=p-10;
                obj.push_back(p);
            }else{
                obj.push_back(p);
                remain=0;
            }
        }
        for(;j>=0;j--){
        	p=b[j]-'0'+remain;
        	if(p>=10){
                remain=1;
                p=p-10;
                obj.push_back(p);
            }else{
                obj.push_back(p);
                remain=0;
            }
		}
		if(remain==1){
			obj.push_back(1);
		}
		for(int k=obj.size()-1;k>=0;k--){
			cout<<obj[k];
		}
		obj.clear();
		cout<<endl;
    }
    
    return 0;
}
乘法稍微改一下就成
#include<iostream>
#include<string>
using namespace std;
int main(){
    string a,b;
    int len1,len2,len3,i,j,k=0;
    cin>>a;
    cin>>b;
    len1=a.length();
    len2=b.length();
    len3=len1+len2;
    int aa[len1+1]={0},bb[len2+1]={0},cc[len3+1]={0};
    for(i=1;i<=len1;i++){
        aa[i]=a[len1-i]-'0';
    }
    for(i=1;i<=len2;i++){
        bb[i]=b[len2-i]-'0';
    }
    for(i=1;i<=len1;i++){
        for(j=1;j<=len2;j++){
            cc[i+j-1]=cc[i+j-1]+aa[i]*bb[j]; //小技巧要注意
        }
    }
    for(i=1;i<=len3;i++){
        cc[i+1]=cc[i+1]+cc[i]/10;
        cc[i]=cc[i]%10;
    }
    while(len3>0&&cc[len3]==0){
        len3--;
    }
    if(len3==0){
        cout<<0<<endl;
    }
    else{
        for(i=len3;i>0;i--){
            cout<<cc[i];
        }
        cout<<endl;
    }
    return 0;
}

10 贪心策略

最优时间分配:
选择结束时间最早的


11 递归与分治

1.子问题要与原始问题相同
2.不能无限制调用本身,必须有个递归出口

阶乘可以用递归

汉诺塔

后期总结补充

分治法

斐波那契数列
#include<iostream>
#include<algorithm>
using namespace std;

int Fibonacci(int n){
	if(n==1||n==0){
		return n;
	}else{
		return Fibonacci(n-1)+Fibonacci(n-2);
	}
}

int main(){
	int n;
	while(cin>>n){
		cout<<Fibonacci(n)<<endl;
	}
} 

子树有多少个节点问题


12 搜索(难度较大,掌握后level上升一个台阶)

广度优先搜索BFS

需要有访问标记
玛雅密码

深度优先搜索DFS

八皇后问题


13 数据结构二


二叉树的遍历

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

struct TreeNode{
	int data;
	TreeNode *leftChild;
	TreeNode *rightChild;
}; 
//前序遍历
void PreOrder(TreeNode *root){
	if(root==NULL){
		return;
	}
	cout<<root->data;
	PreOrder(root->leftChild);
	PreOrder(root->rightChild); 
	return;
} 
//中序遍历 
void InOrder(TreeNode *root){
	if(root==NULL){
		return;
	}
	InOrder(root->leftChild);
	cout<<root->data;	
	InOrder(root->rightChild); 
	return;
}
//后序遍历
void PostOrder(TreeNode *root){
	if(root==NULL){
		return;
	}
	PostOrder(root->leftChild);
	PostOrder(root->rightChild); 
	cout<<root->data;
	return;
}
//层序遍历
void LevelOrder(TreeNode *root){
	queue<TreeNode *>myQueue;
	if(root!=NULL){
		myQueue.push(root);
	}
	while(!myQueue.empty()){
		TreeNode *current=myQueue.front();
		myQueue.pop();
		cout<<current->data;
		if(current->leftChild!=NULL){
			myQueue.push(current->leftChild);
		}
		if(current->rightChild!=NULL){
			myQueue.push(current->rightChild);
		}
	}
	return;
} 
int main(){
	

	
	return 0;
} 

通过先序遍历和中序遍历构建树

https://www.nowcoder.com/questionTerminal/6e732a9632bc4d12b442469aed7fe9ce
(未理解)
#include<iostream>
#include<algorithm>
using namespace std;
struct TreeNode{
	char data;
	TreeNode *leftChild;
	TreeNode *rightChild;
    TreeNode(char c): data(c),leftChild(NULL),rightChild(NULL){}
}; 
TreeNode *Build(string str1,string str2){
    if(str1.size()==0){
        return NULL;
    }
    char c = str1[0];
    TreeNode *root=new TreeNode(c);
    int posion=str2.find(c);
    root->leftChild=Build(str1.substr(1,posion),str2.substr(0,posion));
    root->rightChild=Build(str1.substr(posion+1), str2.substr(posion+1));
    return root;

}
void PostOrder(TreeNode *root){
	if(root==NULL){
		return;
	}
	PostOrder(root->leftChild);
	PostOrder(root->rightChild); 
	cout<<root->data;
	return;
}
int main(){
    string str1,str2;
    while(cin>>str1>>str2){
        TreeNode *root = Build(str1,str2);
        PostOrder(root);
        cout<<endl;
    }
    return 0;
}

二叉排序树

(未理解)
#include<iostream>
#include<algorithm>
using namespace std;

struct TreeNode{
    int data;
    TreeNode *leftNode;
    TreeNode *rightNode;
    TreeNode(int x): data(x),leftNode(NULL),rightNode(NULL){}
};
TreeNode *Insert(TreeNode *root,int x,int father){
    if(root==NULL){
        root=new TreeNode(x);
        cout<<father<<endl;
    }else if(x<root->data){
        root->leftNode=Insert(root->leftNode,x,root->data);
    }else{
        root->rightNode=Insert(root->rightNode,x,root->data);
    }
    return root;
}
int main(){
    int n;
    while(cin>>n){
        TreeNode *root=NULL;
        for(int i=0;i<n;i++){
            int x;
            cin>>x;
            root=Insert(root,x,-1);
        }
        
    }
    return 0;
    
    return 0;
}

优先队列

#include<queue>
优先队列的典型应用:
priority_queue<int>myQueue;
默认是大顶堆

哈夫曼树

哈夫曼树需要改为小顶堆,用greater
priority_queue<int,vector<int>,greater<int>>myQueue;


#include<iostream>
#include<queue>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        priority_queue<int,vector<int>,greater<int>>myQueue;
        while(n--){
            int x;
            cin>>x;
            myQueue.push(x);
        }
        int result=0;
        while(myQueue.size()>1){
            int p=myQueue.top();
            myQueue.pop();
            int q=myQueue.top();
            myQueue.pop();
            result=result+p+q;
            myQueue.push(p+q);
        }
        cout<<result<<endl;
    }
    return 0;
}

散列表

#include<map>

map<int,int>name;

map.empty()
map.size()
map.insert();
map.erase();

[]
at()

find()
clear()

begin()
end()

散列表操作

#include<iostream>
#include<map>
#include<string>
using namespace std;

map<string,int>myMap;

int main(){
	myMap["em"]=67;
	myMap.insert(pair<string,int>("bob",72));
	cout<<myMap.size()<<endl;
	cout<<myMap["bob"]<<endl;
	cout<<myMap.at("em")<<endl;
	myMap.erase("em");
	map<string,int>::iterator it;
	for(it = myMap.begin();it!=myMap.end();it++){
		
		cout<<it->first<<' '<<it->second<<endl;
	}
	myMap.clear();
	it=myMap.find("bob");
	if(it==myMap.end()){
		cout<<"没找到";
	}
	return 0;
	
	
} 

字串计算
注意substr()的使用
#include<iostream>
#include<map>
#include<string>
using namespace std;

int main(){
    string str;
    while(cin>>str){
        map<string,int>count;
        for(int i=0;i<=str.size();i++){
            for(int j=0;j<i;j++){
                string key=str.substr(j,i-j);
                count[key]++;
                
            }
        }
        map<string,int>::iterator it;
        for(it=count.begin();it!=count.end();it++){
            if(it->second>1){
                cout<<it->first<<" "<<it->second<<endl;
            }
        }
    }
    
    return 0;
}

14 图论(really difficult)学会再提升一个level


最小生成树


最短路径 迪杰斯特拉算法


拓扑排序


关键路径

后续更新
(水平有限)



15 动态规划


斐波那契额数列的变体

上楼梯问题
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 92;
long long dp[MAXN];
int main(){
    dp[0]=0;
    dp[1]=1;
    for(int i=2;i<MAXN;i++){
        dp[i]=dp[i-1]+dp[i-2];
    }
    int n;
    while(cin>>n){
        cout<<dp[n+1]<<endl;
    }
    return 0;
}

最大连续子序列和

https://www.nowcoder.com/questionTerminal/df219d60a7af4171a981ef56bd597f7b

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

const int MAXN=1000000;

long long arr[MAXN];
long long dp[MAXN];

long long Max(int n){
    long long maxs=0;
    for(int i=0;i<n;i++){
        if(i==0){
            dp[i]=arr[i];
        }else{
            dp[i]=max(arr[i],dp[i-1]+arr[i]);
        }
        maxs=max(maxs,dp[i]);
    }
    return maxs;
}


int main(){
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            cin>>arr[i];
        }
        long long answer=Max(n);
        cout<<answer<<endl;
    }
    
    return 0;
}
二维:
https://www.nowcoder.com/practice/1c5fd2e69e534cdcaba17083a5c56335?tpId=61&tqId=29506&tPage=1&ru=/kaoyan/retest/1002&qru=/ta/pku-kaoyan/question-ranking

最长递增子序列

设置一个dp[ ]表示以A[ i ]作为末尾的最长递归子序列长度,则最长递增子序列长度是dp[ ]数组中的最大值
两种情况:
A[i]之前的元素都比她大,则dp[ i ]=1;
之前的元素比它小
#include<iostream>
using namespace std;

const int MAXN=1000;

int arr[MAXN];
int dp[MAXN];

int main(){
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            cin>>arr[i];
        }
        int answer=0;
        for(int i=0;i<n;i++){
            dp[i]=arr[i];
            for(int j=0;j<i;j++){
                if(arr[j]<arr[i]){
                    dp[i]=max(dp[i],dp[j]+arr[i]);
                }
            }
            answer=max(answer,dp[i]);
        }
        cout<<answer<<endl;
    } 
    return 0;
}

最长公共子序列

dp[ i ] [ j ]表示以S1[i]和S2[j]作为末尾的最长公共子序列长度
s1[i]==s2[j]  dp[i][j]=dp[i-1][j-1]+1;

s1[i]!=s2[j] dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
 


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

const int MAXN=1001;

char s1[MAXN];
char s2[MAXN];

int dp[MAXN][MAXN];

int main(){
    while(scanf("%s%s",s1+1,s2+1)!=EOF){
        int n=strlen(s1+1);
        int m=strlen(s2+1);
        for(int i=0;i<=n;i++){
            for(int j=0;j<=m;j++){
                if(i==0||j==0){
                    dp[i][j]=0;
                    continue;
                }
                if(s1[i]==s2[j]){      
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
                }
            }
        }
        cout<<dp[n][m];
    }
    
    return 0;
}

背包问题

0-1背包

(未理解)欢迎交流
(记住)
#include<iostream>
using namespace std;

const int MAXN=1001;
int v[MAXN];//价值
int w[MAXN];//重量
int dp[MAXN];

int main(){
    int n,m;
    while(cin>>m>>n){
        for(int i=0;i<n;i++){
            cin>>w[i]>>v[i];
        }
        for(int i=0;i<=m;i++){//初始化
            dp[i]=0;
        }
        for(int i=0;i<n;i++){
            for(int j=m;j>=w[i];j--){  //特别注意要逆序遍历
                dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
        cout<<dp[m]<<endl;
    }
    return 0;
}


完全背包

与0-1背包不同,每种物品可以取不止一件
(未理解)
只需将0-1背包的逆向改为正向即可

其他问题

整数拆分

#include<iostream>
using namespace std;

const int MAXN=1000001;
int dp[MAXN];

int main(){
	dp[0]=1;
	dp[1]=1;
	for(int i=2;i<=MAXN;i++){
		if(i%2==0){
			dp[i]=(dp[i-1]+dp[i/2])%1000000000;
		}
		else{
			dp[i]=dp[i-1];
		}
		
	}
	int n;
	while(cin>>n){
		cout<<dp[n]<<endl;
	}
	return 0;
}

                                                                                                                                                                                                                                                                                2020-9-6于南京NUIST