算法笔记(常用数据结构)
PAT中有些问题把时间转换为以 s 为单位可以简化很多操作。
scanf("%d:%d:%d", &hh, &mm, &ss); //输入格式 int timeToInt(int hh, int mm, int ss){ return hh * 3600 + mm * 60 + ss; } printf("%02d:%02d:%02d\n", sumTime/3600, sumTime%3600/60, sumTime%60); //输出转换为输入形式
2.日期处理
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} } bool isLeap(int year){ //判断是否是闰年 return (year%4==0 && year%100!=0) || (year%400 == 0); }
3.进制转换
//将P进制数x转换为十进制数y int y = 0, product = 1; //product在循环中会不断乘P,得到 1、P、P^2、P^3.... while (x != 0){ y = y + (x%10) * product; // x%10 是为了每次获取x的个位数 x = x / 10; // 去掉x的个位 product = product * P; } //将十进制数y转换为Q进制数z,采用 (除基取余倒排法) int z[40], num = 0; //数组z存放Q进制数y的每一位,num为位数 do{ z[num++] = y % Q; //除基取余 y = y / Q; } while(y != 0); //当商不为0时进行循环
4.最大公约数、最小公倍数
int gcd(int a, int b){ //最大公约数 if(b == 0) return a; if(a < b) return gcd(b, a); else return gcd(b, a%b); } int lcm = (int a, int b){ //最小公倍数 return a*b/gcd(a, b); //a,b的最小公倍数为a*b/最大公约数 //考虑a*b可能溢出,可写为 a/d*b }
5.分数的输入形式
struct Fraction{ long long up, down; //分子、分母 } result; scanf("%lld/%lld", &result.up, &result.down); //分数化简 Fraction reduction(Fraction result){ if(result.down < 0){ //分母为负数,令分子分母都变为相反数 result.up = -result.up; result.down = -result.down; } if(result.up == 0){ //如果分子为0,则令分母为1 result.down = 1; }else{//如果分子不为0,则进行约分 int d = gcd(abs(result.up), abs(result.down)); //分子分母的最大公约数 result.up /= d; result.down /= d; } } //分数的加减乘除
N不会被除自己以外的大于根号N的整数整除(减少运算复杂度)
bool isPrime(int n){ //判断n是否为素数 if(n <= 1) return false; //1即不为素数,也不为合数 int sqr = (int)sqrt(1.0*n); for(int i=2; i<=sqr; i++){ if(n%i == 0) return false; } return true; }
7.C++ sort()排序函数
#include <algorithm> sort( 首元素地址(必填), 尾元素地址的下一个地址(必填), cmp 比较函数(非必填) ); //比较函数不填则默认对前面给出的区间进行递增排序 //提供 cmp 函数实现排序规则 bool cmp(Student a, Student b){ int s = strcmp(a.name, b.name); if(s != 0) return s < 0; //按姓名字典序从小到大排序 else return a.id < b.id; }
符串hash是指将一个字符串映射成为一个整数,使得该整数可以尽可能唯一地代表字符串S。
//A student name consist of 3 capital(大写) English letters plus a one-digit number const int M = 26*26*26*10+1; vector<int> vec[M]; int getID(char name[]){ int id = 0; for(int i=0; i<3; i++){ id = id * 26 + (name[i] - 'A'); } id = id * 10 + (name[3] - '0'); return id; }
9.插入排序
void insertDort(int arr[], int n){//升序 for(int i=1; i<n; i++){ int temp = arr[i], j=i; while(j >0 && arr[i-1] > temp){ arr[j] = arr[j-1]; j--; } arr[j] = temp; } } //简便方法,使用sort函数 void insertDort(int arr[], int n){//升序 for(int i=1; i<n; i++){ sort(arr, arr+i+1); //***** } }
10.归并排序
void mergeSort(int arr[], int n){ for(int step = 2; step/2 <=n; step *= 2){ for(int i=0; i<n; i+=step){ sort(arr+i, arr+min(i+step, n)); //使用sort函数的技巧 } } }
11.二分查找
//前提是数组有序 int binarySearch(int arr[], int left, int right, int x){ int mid; while(left <= right){ mid = (left + right) / 2; if(arr[mid] = x) return mid; //找到解,返回mid else if(arr[mid] < x) left = mid + 1; else right = mid -1; } return -1; //解不存在 }
//在a[i+1]~a[n-1]中查找第一个超过a[i]*p的数,返回其位置给j int j = upper_bound(arr+i+1, arr+n, (long long)arr[i]*p) - arr; //在a[i+1]~a[n-1]中查找第一个大于或等于a[i]*p的数,返回其位置给j int j = upper_bound(arr+i+1, arr+n, (long long)arr[i]*p) - arr;
12.数组中两个数据交换使用 swap()函数
swap(arr[1], arr[2]);
13.常用定义静态链表的格式
struct Node{ int address; //结点地址 int data; //数据域 int next; //指针域 int order; //结点在链表上的序号 XXX; // } node[100]; //结点的某个性质,不同的题目会有不同的设置
14.质因子分解
//对一个整数n来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于 sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其余质因子全部小于等于sqrt(n) struct factor{ int x, cnt; //x为质因子,cnt为其个数 }fac[10]; if(n%prime[i]==0){ //prime为质数表,如果prime[i]是n的因子 fac[num].x = prime[i]; //记录该因子 fac[num].cnt = 0; while(n%prime[i] == 0){ //计算出质因子prime[i]的个数 fac[num].cnt++; n /= prime[i]; } num++; //不同质因子个数加 1 } if(n!=1){ //如果无法被根号n以内的质因子除尽 fac[num].x = n; //那么一定有一个大于根号n的质因子 fac[num++].cnt = 1; }
15.计算n!中有多少个质因子p
int cal(int n, int p){ int ans = 0; while(n){ ans += n/p; //累加n/p^k n /= p; //相当于分母多乘一个p } return ans; }