算法笔记(胡凡)学习笔记@Kaysen

        本文旨在记录算法笔记学习过程中的收获和一些知识点,部分易错知识点只针对个人而言,CCF-CSP考试冲鸭!!!

Chapter 2 C/C++快速入门(易错知识点)

2.1 基本数据类型

        变量定义注意区分大小写。

一、整型

        整型int,32bit(4Byte),取值范围是-2^{31}\sim (2^{31}-1)绝对值在10^{9}范围内的整数都可以定义成int

        长整型long long,64bit(8Byte),取值范围是-2^{63}\sim(2^{63}-1)绝对值超过2.1\times 10^{9}的整数就需要用long long存储。

        如果long long型赋大于2^{31}-1的初值,则需要在初值后加上LL,否则编译错误。

二、浮点型  

        单精度浮点float,取值范围-2^{128} \sim 2^{128},有效精度只有6~7位。

        双精度浮点double,取值范围-2^{1024}\sim2^{1024},有效精度有15~16位。

        尽量不要使用float,浮点型数据使用double存储。

2.2 顺序结构

一、使用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位小数输出,舍入规则:“四舍六入五成双”

2.5 数组

2.5.4 memset——对数组的每个元素赋相同的值

        使用memset( )必须在程序开头添加string.h头文件。使用格式:

memset(数组名,值,sizeof(数组名))

        注意:memset( )是按字节赋值!

2.7 指针

2.7.5 引用(c++)

        引用(&)不产生副本,只是给原变量取了别名。

        对引用变量的操作就是对原变量的操作。

        使用引用变量简化了指针的使用。

2.8 结构体

2.8.3 结构体的初始化

        *引入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. 只要参数个数不同,可以定义多个构造函数。

Chapter 3 入门模拟

3.1 简单模拟

PAT B1032 挖掘机技术哪家强

//题目请查看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;
}

3.4 日期处理

codeup 1928 日期差值

        解决日期差值问题,只需要通过增加小日期,通过比较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

Chapter 4 算法初步

4.1 排序

4.1.1 选择排序

        简单选择排序:进行n趟操作,每趟从待排序的部分[i,n]选择最小的(或最大,由升序或者降序决定)元素,令其与A[i]交换,则[0,i]就变得有序了。

        总的时间复杂度为O(n^2)。

4.1.2 插入排序

        直接插入排序:对A[1~n],令i=2开始枚举,进行n-1趟操作,每次将第i位插入到有序部分A[1~i-1]。

4.1.3 sort函数应用

        参见第6.9.6节。

4.2 散列

4.2.1 散列(hash)定义与整数散列

        将元素(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连接成一个单链表。

4.2.2 字符串hash初步

        将字母A~Z,a~z表示为进制数,如字符串中只含有A~Z,则转换为26进制数,再将其用于hash计算。

4.3 递归

4.3.1 分治

        分解-解决-合并。

4.3.2 递归

        递归边界、递归式

        n皇后问题。

4.4 贪心

4.4.1 简单贪心

        贪心法:考虑在当前状态下局部最优(或较优)的策略。来使全局的结果达到最优(或较优)

4.5 二分

4.5.3 快速幂

        例如求,利用常规循环求解的时间复杂度是O(b)。

        快速幂解法:基于二分思想

        1. 如果b是奇数,有a^{b}=a*a^{b-1}

        2. 如果b是偶数,有a=a^{b/2}*a^{b/2}

        在经过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=k_{n}k_{n-1}...k_{2}k_{1}k_{0}=2^{k_{n}}+2^{k_{n-1}}+...+2^{k_2}+2^{k_1}+2^{k_0}。所以可以将a^{b}表示为a^{2^{k_n}+....2^{k_0}},迭代解法:

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

4.6 two pointers

4.6.2 归并排序

        2-路归并排序的原理是:

        将序列两两分组,将序列归并为\left \lceil n/2 \right \rceil个组,组内单独排序;然后将这些组两两合并,生成\left \lceil n/4 \right \rceil个组,组内单独排序;以此类推,直到只剩下一个组为止,归并排序的时间复杂度是O(nlogn)。

4.6.3 快速排序

        快速排序的时间复杂度是O(nlogn)。

        快速排序的原理:

        1. 选定一个主元,将序列中不超过他的数放在他的左侧,比他大的数放在他的右侧;

        2. 然后再分别从两侧的子序列中选择主元进行快速排序,直到调整区间不超过1。

        当序列接近有序时会达到最坏的情况,时间复杂度为O(n^2),随机选择主元能够将对于任意输入的时间复杂度降低到O(nlogn)。

Chapter 5 数学问题

5.2 最大公约数(gcd)和最小公倍数(lcm)

        欧几里得算法

你可能感兴趣的:(算法)