文章目录
00-算法的基本概念
- 算法:通俗来说,就是解题步骤
- 算法的分类(按照实现策略)
- 暴力法:其实就是穷举
- 增量法:比如插入排序
- 分治法:
- 贪心算法
- 动态规划法
- 回溯法
- 分支界限法 - 如何区分算法优劣
- 时间复杂度:执行算法所需要的计算工作量
- 空间复杂度:算法需要消耗的内存空间
- 考虑时间复杂度的必要性
- 不同的机器计算速度不一样
- 计算机资源有限,输入数据量很大的情况下,不同算法消耗时间差极大
- 基本指令:它是程序执行消耗的时间单位
- 算术指令:加减乘除等
- 数据移动指令:赋值,拷贝等
- 控制指令:if,while,return等语句
- 计算以下代码的运行时间为3N+2
for (int i = 0; i < N; i++)
{
cout << "hello" << endl;
}
// int i = 0; 赋值操作,执行1次
// i<N判断操作,执行N+1次
// cout,打印操作,执行N次
// i++自增操作,执行N次
// 故总共N+1次
- T(n)的提出
- 不同的输入,算法执行消耗的时间是不同的。
- 我们不需要分析一个算法在某种输入情况下,其消耗时间是多少
- 我们直接将其消耗的时间表示成输入规模n的函数:T(n)
- 不同的算法,消耗的时间T(n)随着输入规模n的增长速度,是不同的
int a = 1;
int b = 2;
int c = 3;
// T(n) = 3
for (int i = 0; i < n; i++)
{
cout << "hello" << endl;
}
// T(n) = 3n + 2
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
cout << "hello" << endl;
}
}
// T(n) = 3n^2 + 4n +2
时间复杂度详解
- 复杂度的大O(n)表示法
- 对于给定的函数g(n),用O(g(n))来表示以下集合: O(g(n)) = f(n)
- 其中,存在正常量c和N,使得所有的大于等于N的n值,
- 均有0 = <f(n) <= cg(n)
- 算法分析中,一般有大O符号来表示函数的渐进上界
- 其含义是:当数据量达到一定程度是,g(n)的增长速度不会超过O(g(n))的限定范围
- 可见,大O表示法,表示的是算法的时间随规模n的增长速度
- 对于给定的函数g(n),用O(g(n))来表示以下集合: O(g(n)) = f(n)
- 常用的时间复杂度
- O(1)
- O(log(n))
- O(n的开方)
- O(n)
- O(nlog(n))
- O(n^2)
- O(e^n)
- O(n!)
空间复杂度
- 有时间递归调用,需要计算调用栈所需要的内存空间
算法的分类:暴力法
- 暴力法其实就是穷举法
算法的分类:增量法
- 应用场景:
- 插入排序
算法的分类:分治法
-
分而治之
- 问题的规模越小,越容易解决
- 把复杂问题不断分成相同或相似的问题,直到每个子问题可以简单地进行求解
- 将所有子问题的解合并起来,就是原问题的解
-
分治和递归
- 产生的子问题往往和原问题相同,它只是原问题的较小规模的表达
- 使用递归手段求解子问题,可以容易地将子问题的解合并,得到原问题的解
-
应用场景
- 二分搜索
- 大整数乘法
- 归并排序
- 快速排序
- 棋盘覆盖问题
- 循环赛日程表问题
- 汉诺塔问题
算法的分类:贪心算法
- 定义:不从整体考虑,只考虑眼前,得到局部最优解。总是做出当前看来是最好的选择
- 要保证最终得到的是全局最优法,贪心策略必须具有无后效性
- 适用场景:
- 用贪心法直接求解全局最优,条件比较苛刻
- 哈夫曼编译