本文旨在记录算法笔记学习过程中的收获和一些知识点,部分易错知识点只针对个人而言,CCF-CSP考试冲鸭!!!
变量定义注意区分大小写。
一、整型
整型int,32bit(4Byte),取值范围是,绝对值在范围内的整数都可以定义成int。
长整型long long,64bit(8Byte),取值范围是,绝对值超过的整数就需要用long long存储。
如果long long型赋大于的初值,则需要在初值后加上LL,否则编译错误。
二、浮点型
单精度浮点float,取值范围,有效精度只有6~7位。
双精度浮点double,取值范围,有效精度有15~16位。
尽量不要使用float,浮点型数据使用double存储。
一、使用scanf和printf输入/输出
scanf的%c是可以读入空格和换行的,因此在scanf的格式符选择上一定要注意是否能够正确读入需要输入的数据。
scanf对除%c以外,其他格式符的输入以空白符(空格、Tab)为结束判断标志;字符数组使用%s读入时以空格跟换行为读入结束标志。例如:
char str[10];
scanf("%s",str);
printd("%s",str);
上述代码段运行时,输入/输出结果如下:
//输入数据:
abcd efg
//输出数据:
abcd
即,abcd和efg之间的空格作为了scanf()读入字符数组结束的标志。
常用的输出格式:
(1)%md:使不足m位的int型变量以m位右对齐输出,高位以空格补齐;多于m位的变量原样输出。
(2)%0md:使不足m位的int型变量以m位右对齐输出,高位以0补齐;多于m位的变量原样输出。
(3)%.mf:让浮点数保留m位小数输出,舍入规则:“四舍六入五成双”。
使用memset( )必须在程序开头添加string.h头文件。使用格式:
memset(数组名,值,sizeof(数组名))
注意:memset( )是按字节赋值!
引用(&)不产生副本,只是给原变量取了别名。
对引用变量的操作就是对原变量的操作。
使用引用变量简化了指针的使用。
*引入c++的构造函数进行初始化,可以简化结构体的初始化操作。
一、构造函数
在结构体中定义的,用于初始化结构体的一种函数。
特点:不需要写返回类型,函数名与结构体名相同。
一个结构体可以有多个构造函数,可以对部分结构体内变量进行初始化。
struct studentInfo{
int id;
char gender;
//默认生成的构造函数
studentInfo(){}
//只初始化gender
studentInfo(char _gender){
gender = _gender;
}
//初始化id和gender
studentInfo(int _id,char _gender){
id = _id;
gender = _gender;
}
};
注意:1.如果自定义了构造函数,不能不经初始化就定义结构体变量。(此时默认的构造函数已经不存在)
2. 只要参数个数不同,可以定义多个构造函数。
//题目请查看PAT官网https://pintia.cn/problem-sets/994805260223102976/problems/994805289432236032
//利用数组即可实现相应功能
int scores[MAXN] = {0};
int main() {
int i = 0, N = 0;
int school = 0, score = 0;
scanf("%d", &N);
for (i = 0; i < N; i++) {
scanf("%d%d", &school, &score);
scores[school] += score;
}
int flag = 0, max = 0;
for (i = 1; i <= N; i++) {
//这里循环条件必须是1~N,否则测试点2,不能通过测试
if (scores[i] > max) {
flag = i;
max = scores[i];
}
}
printf("%d %d", flag, max);
return 0;
}
解决日期差值问题,只需要通过增加小日期,通过比较day和当月日期,month和12的大小关系,实现月、年的增加即可,注意控制条件。
int isleapyear(int year);
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}
};
//用于存储平年(第0维)和闰年(第1维)各月的天数
int main() {
int date1 = 0, date2 = 0;
int year = 0, mon = 0;
int day = 0, leap = 0;
while (scanf("%d%d",&date1,&date2) != EOF) {
if (date1 > date2) {
int temp = date1;
date1 = date2;
date2 = temp;
}
int count = 1;
while (date1 != date2) {
count++;
date1++;
year = date1 / 10000;
mon = (date1 % 10000) / 100;
day = date1 % 100;
leap = isleapyear(year);
if (day > month[mon][leap]) {
date1 = year * 10000 + (mon + 1) * 100 + 1;
}//如果day的值超过了本月最大天数,月数增加
year = date1 / 10000;
mon = (date1 % 10000) / 100;
if (mon > 12) {
date1 = (year + 1) * 10000 + 101;
}//如果mon的值大于12,年份增加
}
printf("%d\n", count);
}
}
int isleapyear(int year) {
if ((year % 100 != 0&& year % 4 == 0) || year % 400 == 0) {
return 1;
}
return 0;
}
2021.08.12
简单选择排序:进行n趟操作,每趟从待排序的部分[i,n]选择最小的(或最大,由升序或者降序决定)元素,令其与A[i]交换,则[0,i]就变得有序了。
总的时间复杂度为O(n^2)。
直接插入排序:对A[1~n],令i=2开始枚举,进行n-1趟操作,每次将第i位插入到有序部分A[1~i-1]。
参见第6.9.6节。
将元素(key)通过一个函数(H)转换为整数,使得该整数可以尽量唯一地代表这个元素。
除留余数法:
H(key)=key%mod(mod一般直接取表长Tsize)
因为对于不同key的hash值可能相同,所以需要解决冲突:
1. 线性探查法:
依次探查H(key)+i(i=1,2,...)是否被占用。超过表长则回到0开始探查。
2. 平方探查法:
依次探查H(key)+i^2是否被占用,注意不能是负数,对于负数对表长求模。
3. 链地址法:
将H(key)相同的key连接成一个单链表。
将字母A~Z,a~z表示为进制数,如字符串中只含有A~Z,则转换为26进制数,再将其用于hash计算。
分解-解决-合并。
递归边界、递归式
n皇后问题。
贪心法:考虑在当前状态下局部最优(或较优)的策略。来使全局的结果达到最优(或较优)
例如求,利用常规循环求解的时间复杂度是O(b)。
快速幂解法:基于二分思想
1. 如果b是奇数,有
2. 如果b是偶数,有
在经过log(b)级别次数转换后,可以把b变成0;任何正整数的0次方是1。
快速幂的递归写法:
typedef long long LL;
//求a^b%m递归写法
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);
//注意此处必须以另一个变量来接收binaryPow()返回值,否则两次调用binaryPow()并未减少时间复杂度。
return mul * mul % m;
}
}
注意:1. 如果初始a可能大于m,则先对m取模
2. 如果m=1,则可以直接判断为0。
快速幂的迭代写法:
将b按二进制展开可以表示为b==。所以可以将表示为,迭代解法:
1. 如果b的第i位(第i次迭代,处理时是最低位)为1,则ans=ans*a%m。
2. a=a*a%m
3. b右移一位,相当于除2。
typedef long long LL;
//求a^b%m递归写法
LL binaryPow(LL a, LL b, LL m) {
LL ans = 1;
while (b>0) {
if (b & 1 == 1) { //该位为1说明需要累积。
ans = ans * a % m;//令ans累积上a
}
a = a * a % m;
b >>= 1;
}
return ans;
}
2-路归并排序的原理是:
将序列两两分组,将序列归并为个组,组内单独排序;然后将这些组两两合并,生成个组,组内单独排序;以此类推,直到只剩下一个组为止,归并排序的时间复杂度是O(nlogn)。
快速排序的时间复杂度是O(nlogn)。
快速排序的原理:
1. 选定一个主元,将序列中不超过他的数放在他的左侧,比他大的数放在他的右侧;
2. 然后再分别从两侧的子序列中选择主元进行快速排序,直到调整区间不超过1。
当序列接近有序时会达到最坏的情况,时间复杂度为O(n^2),随机选择主元能够将对于任意输入的时间复杂度降低到O(nlogn)。
欧几里得算法