【算法】算法技巧&模板-总结

本文详细总结了算法竞赛中常用的编程技巧,包括日期判断、多点测试输入、浮点数比较、结构体比较、随机数生成、二分搜索等基础操作,并深入介绍了math.h数学操作、字符串处理、背包问题的二进制解法、进制转换和快速幂算法。同时,讲解了排序算法如冒泡、选择和插入排序,以及常用字符串和字符处理函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

  算法技巧总结
  



基础知识

  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;
    }
}

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值