前言
算法技巧总结
文章目录
基础知识
OJ每秒运算次数 10e7~10e8
万能头:# include <bits/stdc++.h>
memset : 对数组中每一个元素赋相同的值 需string.h头文件 (建议只赋0,-1)
memset (数组名,值,sizeof(数组名) )
long long 的范围是 [-2的63次方,2的63次方) 64位二进制补码表示
字符转ASCII码 : (int)a ASCII码转字符:(char)a
散列 hash : 以空间换时间 bool hashtable[100010]
策略:把输入的数作为数组的下标来对这个数的性质进行统计
将元素通过一个函数转换为整数,使得该整数可以尽量唯一的代表这个元素
hashtable数组的大小只要能把题目给出的字符包括即可,一般可以直接设置ASCII码的个数128为其数组长度
基础操作
1.日期题
判断是否闰年
1.年份是400的倍数
2.年份是4的倍数,但不是100的倍数
bool isLeap(int year){ //判断是否闰年
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
平闰年每月天数
int month[13][2]={ //平年和闰年的每个月的天数
{0,0},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},
{31,31},{31,31},{30,30},{31,31},{30,30},{31,31}
};
判断是否满当月天数
if( d1 == month[m1][isLeap(y1)] + 1 ) //判断是否满 当月天数
2.多点测试输入
当输入的两个a和b都为0时结束输入
while(cin>>a>>b,a||b)
while(scanf("%d%d",&a,&b),a||b)
3.浮点数比较
const double eps=1e-8;
fabs(a-b) < eps
4.结构体比较
bool cmp(Student a,Student b){
if(a.score!=b.score) return a.score>b.score;
else return strcmp(a.name,b.name)<0;
}
5.生成随机数
#include<stdlib.h>
int mian(){
srand((unsigned)time(NULL));
printf("%d",rand());
}
rand范围是[,RAND_MAX]
想要输出[a,b] : rand()%(b-a+1)+a
或者 (int)((double)rand()/32767*(b-a+1)+a) 32767指RAND_MAX
6.二分
upper_bound(first,last,value) 返回第一个大于value的值的位置
lower_bound(first,last,value) 返回第一个大于等于value的值的位置
数学操作
1.math.h头文件
① fabs(double x) :对double型变量取绝对值
floor 向下取整 ceil 向上取整
② pow(double r,double p) : 返回r的p次方
sqrt 返回算数平方根 log 返回以自然对数为底的对数
③ sin(double x) cos tan 参数为弧度制
const double pi=acos(-1.0);
double db1= sin(pi*45/180);
printf("%f",db1);
输出:0.707107
④ round(double x) :对x四舍五入 ,返回类型为double,需进行取整
double db1=round(3.40);
printf("%d",(int)db1);
⑤ 求圆周率Pi
const double Pi=acos(-1.0);
字符串操作
1.字符串输入
char a[N];
cin>>a+1;
2.字符串长度计算
strlen( )的参数必须是char*
str.length( )是string类对象str调用的成员函数
char* ch="abcdef";
string str="abcdefg";
cout<<str.length();
// cout<<strlen(str); 出错
cout<<strlen(ch);
// cout<<ch.length(); 出错
3.存储多个字符串
char g[N][N];
for(int i=1;i<=n;i++)
cin>>g[i]; //cin>>g[i]+1;
4.部分函数
用于字符判断的函数,若是返回非0,否则返回0
isalnum()
判断输入的字符是否为字母或者数字,即是否在 “A – Z” 或者 “a – z” 或者"0 – 9"之间
isdigit()
判断输入的字符是否是数字
isalpha()
判断输入的字符是否为字母,即是否在 “A – Z” 或者 "a – z"之间
islower()
判断字符是否小写字母
isupper()
判断字符是否大写字母
isblank()
判断输入字符是否为空格,或者tab键制表符,即space 和 \t
isspace()
判断输入字符是否为 空格,或者tab键制表符,’\r’ 或 ‘\n’ 等
用于字符转换的函数,参数输入为字符类型
toupper()
将一个字符转换为大写
tolower()
将一个字符转换为小写
string的find函数
用于在字符串s中查找子字符串s1,若能找到则返回s1在s中首次出现时其首字符的索引(从0开始);否则,返回string::npos
if(s2.find("could")!=s2.npos && str[i+1]=="you")
stringstream
istringstream:流的输入
ostringstream:流的输出
stringstream:输入输出
stringstream 类主要用来进行数据类型的转换,由于使用string对象来代替字符数组(snprintf方式),就避免缓冲区溢出的危险;而且,因为传入参数和目标对象的类型会被自动推导出来,所以不存在错误的格式化符的问题。简单说,相比c库的数据类型转换而言, 更加安全、自动和直接。
#include <iostream>
#include <sstream>
using namespace std;
int main(){
string str = "hello world";
cout << str << endl;
stringstream ss(str); //将str复制到ss
string abc;
while(ss >> abc){ //相当于输入一个个的单词
cout << abc <<endl;
}
return 0;
}
//输出:
//hello world
//hello
//world
背包问题
1.二进制解法
for(int k=1;k<=s;k*=2){ //s个商品,将s划分
s-=k;
goods.push_back({v*k,w*k});
}
if(s>0)
goods.push_back({v*s,w*s});
进制转换
1.P进制数x转换为十进制数y
int y=0,product=1;
while(x!=0){
y=y+(x%10)*product;
x=x / 10;
product=product * P;
}
2.十进制数y转换为Q进制数z
int z[40],num=0; //数组z存放Q进制数y的每一位,num为位数
do{
z[num++]=y % Q;
y=y/Q;
}while(y!=0);
快速幂
核心思想就是每一步都把指数分成两半,而相应的底数做平方运算
if(b%2==1) 可以替换为if (b&1)
a:base b:power
1.基础写法
long long fastPower(long long base, long long power) {
long long result = 1;
while (power > 0) {
if (power % 2 == 0) {
//如果指数为偶数
power = power / 2;//把指数缩小为一半
base = base * base % 1000;//底数变大成原来的平方
} else {
//如果指数为奇数
power = power - 1;//把指数减去1,使其变成一个偶数
result = result * base % 1000;//此时记得要把指数为奇数时分离出来的底数的一次方收集好
power = power / 2;//此时指数为偶数,可以继续执行操作
base = base * base % 1000;
}
}
return result;
2.递归写法
typedef long long LL;
LL binaryPow(LL a,LL b,LL m){
if(b==0) return 1;
if(b%2==1) return a*binaryPow(a,b-1,m)%m;
else{
LL mul=binaryPow(a,b/2,m);
return mul*mul % m;
}
}
3.迭代写法
typedef long long LL;
LL binaryPow(LL a,LL b,LL m){
LL ans=1;
while(b>0){
if(b&1){
ans=ans*a % m;
}
a=a*a % m;
b>>=1; //将b的二进制右移1位,即b=b/2
}
}
排序
1.冒泡排序
for(int i=0; i<=n-1 ;i++){ //进行n-1趟
//第i趟时从a[0]到a[n-i-1]都与它们下一个数比较
for(int j=0 ; j<n-i-1 ; j++){
if(a[j]>a[j+1]){
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
2.选择排序 O(n2)
void selectSort(){
for(int i=1;i<=n;i++){ // 进行n趟操作
int k=i;
for(int j=i;j<=nlj++){ //选出[i,n]中最小的元素,下标为k
if(A[j]<A[k])
k=j;
}
int temp=A[i]; //交换A[k]与A[i]
A[i]=A[k];
A[k]=temp;
}
}
3.插入排序
int A[maxn],n;
void insertSort(){
for(int i=2;i<=n;i++){ //n-1趟排序
int temp=A[i],j=i;
while(j>1&&temp<A[j-1]){ //只要temp小于前一个元素A[j-1]
A[j]=A[j-1]; //把A[j-1]后移一位至A[j]
j--;
}
A[j]=temp;
}
}