排序
选择排序
思想:
迭代n-1次,
维持循环不变式:
第k次迭代前
前k-1个元素均是有序的。且前k-1是有序排列下最前面的k-1个元素。
插入排序
思想:
迭代n-1次
维持循环不变式:
第k次迭代前
前k-1个元素均是有序的
C标准库的快速排序
...
散列
散列的定义与整数散列
常用Hash函数介绍:
- 除留余数法
H(Key) = Key % mod,一般mod选择为一个素数。
解决冲突:
1. 线性探查法
H(Key),H(Key)+1,...
2. 平方探查法
H(Key)+1^2, H(Key)-1^2,H(Key)+2^2, H(Key)-2^2,...
3. 链地址
一般下可直接使用标准库提供的设施
字符串hash初步
ASCII中'a'的码值97,'A'是65,'0'是48。
递归
分治
迭代
贪心
简单贪心
区间贪心
二分
二分查找
二分法扩展
对应的问题类型:单调区间寻找指定位置
快速幂
two pointers
什么是two pointers
归并排序
递归实现
左半边有序
右半边有序
左右合并
迭代实现
快速排序
选取主元
按主元进行区间划分
左边区间有序
右边区间有序
// 随机快排:避免特定输入下必然导致最差效率的情况
生成指定范围[a,b]内的随机数
#include <stdlib.h>
srand((unsigned)time(NULL));
int k = (int)round(1.0*rand()/RAND_MAX * (b-a) + a);
其他高效技巧与算法
打表
活用递推
随机选择算法
入门篇--数学问题
简单数学
最大公约数与最小公倍数
最大公约数
求解最大公约数:
给定a,b均为正整数,求a,b的最大公约数
- 令min,max,分别代表a,b中较小者和较大者
- 1.gcd(a,b)=gcd(min, max % min),利用此公式将一个较大规模问题转化为一个较小规模同类问题
- 2.gcd(a,0)=a。给出边界。
int gcd(int a, int b)
{
if(b==0) return a;
else return gcd(b, a%b);
}
最小公倍数
正整数a,b的最小公倍数 = (ab)/(ab的最大公约数)
分数的四则运算
分数的表示和化简
分数的表示
假分数
struct Fraction
{
int up, down;
};
- 使down为非负数。如分数为负,令分子up为负即可。
- 如该分数恰为0,则规定其分子为0,分母为1。
- 分子和分母没有除了1以外的公约数。
分数的化简
主要用来使Fraction变量满足分数表示的三项规定
- 如分母down为负数,则令分子up和分母down都变为相反数
- 如分子up为0,则令分母down为1
- 约分,求分子绝对值和分母绝对值的最大公约数d,令分子,分母同时除以d
分数的输出
- 输出分数前,先对其化简
- 如分数r的分母down为1,说明该分数是整数,一般作为整数输出
- 如分数r的分子绝对值大于分母,按带分数形式输出
printf("%d %d/%d", r.up / r.down, abs(r.up) % r.down, r.down)
素数
素数又称质数,指除了1和本身之外,不能被其他整数除的一类数。
对任意除了1的正整数,不是素数,就是合数。
1既不是素数,也不是合数
素数的判断
加快素数的判定
如在[2, n-1]中存在n的约数,设为k
即n%k == 0
则由k *(n/k)==n可知,
n/k也是n的一个约数
且k与n/k中一定满足其中一个小于等于sqrt(n),另一个大于等于sqrt(n)
只需要判定n能否被2,3,...,(int)sqrt(n)中的一个整除,即可判定n是否为素数,算法复杂度O(sqrt(n))
素数表的获取
方法1
对范围内每个数,依次使用上述素数判别进行判别
方法2
1. 2是素数,去掉所有2的倍数
2. 3依然存在,故是素数,去掉所有3的倍数
3.下一个存在的是5,是素数,去掉所有5的倍数
...
该算法求解范围内所有数中素数子集效率较高
质因子分解
正因子分解指将一个正整数n写成一个或多个质数的乘积的形式
以下讲解针对大于1的正整数
由于每个质因子可不止出现一次,定义结构体factor存放质因子及其个数
struct factor
{
// 质因子
int x;
// 个数
int cnt;
}fac[10];
对一个int型范围的数,fac数组大小到10即可
对一个正整数n来说,
如它存在[2,n]范围内的质因子,
要么这些质因子全部小于等于sqrt(n)
要么只存在一个大于sqrt(n)质因子
质因子分解:
- 枚举[1, sqrt(n)]范围内所有质因子p,判断p是否是n的因子
如果p是n的因子,给fac数组增加质因子p,初始化其个数为0
只要p还是n的因子,就让n不断除以p,每次操作令p的个数加一,直到p不再是n的因子
如果p不是n的因子,直接跳过
- 如在上面步骤后,n仍然大于1,说明n有且仅有一个大于sqrt(n)的质因子
把这个质因子加入fac,令其个数为1
时间复杂度sqrt(n)
大整数运算
对A+B
如A和B有1000个数位
大整数的存储
struct bign
{
int d[1000];
int len;
bign()
{
memset(d, 0, sizeof(d));
len = 0;
}
};
为了处理的方便,一般数组高索引位存储十进制形式的高位,索引0存储十进制下的个位
输入大整数时,一般先用字符串读入
再把字符串另存为bign结构体
大整数比较
略
大整数的四则运算
加法
低位相加,进位
减法
大数减去小数,余量确定时额外看下一位是否要给予增量,如果下一位两者相等,则需要持续往下看,直到看到不同
乘法
从低位到高位迭代
每次迭代处理
计算迭代位和乘数1相乘结果+之前累积余量,得到结果的低位作为本位结果,减去低位余量作为累积余量继续迭代
除法
扩展欧几里得算法
扩展欧几里得算法
ax+by=c求解
ax ≡ c(modm)
a≡b(mod m),或记为a≡b(m)
即为(a-b)%m=0