持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
数据结构:DS
- 线性表:顺序表、链表
- 栈、队列
- 树形结构
- 排序算法
- 查找
- 图
时间复杂度
在数据大小(规模)发生变化时,算法的执行时间如何变化?
时间复杂度从小到大排列为: O(1) 常数级 => n条语句 O(logn) 对数级 => 二分查找 O(n) 线性 O(nlogn) 线性对数 => 快速排序 O(n²) 平方级 O(n³) 立方级 O(2^n) 指数级 O(N!)
时间复杂度遵循的几个原则:
- 加法原则:并列、累加
- 乘法原则:嵌套关系(O(n²))
- 常数可以被化简掉(数字可以约掉)
- 约掉小的数量级,保留大的数量级。对于下列这种式子,也是可以进行约掉的
O(nlogn + n²) => O(n²)
思考:时间复杂度为O(n)的算法,一定比O(n²)的算法快么? 在数据规模足够大的情况下,O(n)的算法比O(n²)的执行时间要快。
- 常数不确定
- 数据规模不确定
空间复杂度
在算法的数据规模发生变化时,消耗的空间(内存空间)如何跟着变化? O(1) n个变量 O(logn) 递归的深度 O(n) 一维数组 O(n²) 二维数组
示例
#include <stdio.h>
int main() {
// Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?
/**
* 滑动窗口法
* 连续13个数字的乘积,时间复杂度O(2n)=>O(n)
* now: 当前窗口乘积
* ans:最终答案(最终答案) 23514624000
* cnt:计数器 窗口当中0的数量
* 如果加进窗口里面的值是0,这个数字就不乘,计数器加1
* 一旦某一时刻出窗口的数字是0,不除,计数器减去1
* 更新答案时:必须保证计数器为0时才可以更新答案
* 即:进窗口、出窗口、更新答案时,都需要进行判断
*/
char str[1005]; // 长度至少是1001,所以开到1005
scanf("%s", str);
long long now = 1, ans = 0, cnt = 0;
for(int i = 0; i < 1000; i++){
// 前13位是没有0的,所以可以直接初始化
if (i < 13) {
// 为什么要减去字符'0'? 字符数组中是以字符的形式存储的,通过减去字符'0'可以得到相应的数字。比如'9' - '0' => 9
now *= str[i] - '0'; // 直接把新加入的数字诚到窗口当中作为乘积
} else {
// 判断新进来的这一位是否为0。
// 进窗口——是0:计数器加1; 不是0:直接乘进来
// 出窗口——是0:计数器减1; 不是0:除掉
if (str[i] == '0') {
cnt++;
} else {
now *= str[i] - '0';
}
if (str[i - 13] == '0') {
cnt--;
} else {
now /= str[i - 13] - '0';
}
}
// 更新答案:当前窗口没有0,并且ans小于当前窗口的乘积
if (cnt == 0 && ans < now) {
ans = now;
}
}
// %d 输出的是 int,
// %ld 输出的是 long,
// %lld 输出的是 long long;
//
// 32位编译器:
// int 4字节
// long 4字节
// long long 8字节
//
// 64位编译器:
// int 4字节
// long 8字节
// long long 8字节
printf("%lld\n", ans); // %lld %d=int, %ld=long, %lld=long long;
return 0;
}