算法复杂度主要从时间、空间两个角度评价:
- 时间:假设运行时间固定,统计算法运行的「计算操作的数量」,以代表算法运行所需时间;
- 空间:统计在最差情况下,算法运行所需使用的「最大空间」
时间复杂度具有最差
、平均
、最佳
三种情况,分别使用 O , Θ , Ω三种符号表示。
常见种类
根据从小到大排列,常见算法 时间 复杂度主要有:
O(1) < O(logN) < O(N) < O(NlogN) < O(N2) < O(2N) < O(N!)
O(1):
1)运行次数与N大小呈常数关系:
int algorithm(int N) {
int a = 1;
int b = 2;
int x = a * b + N;
return 1;
}
2)以下代码,无论 a 取多大,都与输入数据大小 N 无关:
int algorithm(int N) {
int count = 0;
int a = 10000;
for (int i = 0; i < a; i++) {
count++;
}
return count;
}
O(N):
1)递归求阶乘(N !=1×2×3×…×N):
int algorithm(int N){
if(N==1)
return 1;
else
return N*algorithm(N-1);
}
2)对于以下代码,虽然是两层循环,但第二层与 N大小无关,因此整体仍与 N呈线性关系:
int algorithm(int N) {
int count = 0;
int a = 10000;
for (int i = 0; i < N; i++) {
for (int j = 0; j < a; j++) {
count++;
}
}
return count;
}
O(N2):
1)两层循环相互独立,都与 N 呈线性关系:
int algorithm(int N) {
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
count++;
}
}
return count;
}
2)冒泡排序(冒泡排序的总体时间复杂度为 O(N2))
算法思路:
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
代码实现:
int[] bubbleSort(int[] nums) {
int N = nums.length;
for (int i = 0; i < N - 1; i++) {
for (int j = 0; j < N - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
//交换数据
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
return nums;
}
O(2N):
算法中,指数阶常出现于递归
,代码如下:
int algorithm(int N) {
if (N <= 0)
return 1;
int count_1 = algorithm(N - 1);
int count_2 = algorithm(N - 1);
return count_1 + count_2;
}
O(N!) :
阶乘阶对应数学上常见的 “全排列” 。即给定 N 个互不重复的元素,求其所有可能的排列方案,则方案数量为:N (N - 1) × (N - 2) × … × 2 × 1 =N !
阶乘
常使用递归实现,算法原理:第一层分裂出 N个,第二层分裂出 N - 1个,…… ,直至到第 N 层时终止并回溯。
int algorithm(int N) {
if (N <= 0) return 1;
int count = 0;
for (int i = 0; i < N; i++) {
count += algorithm(N - 1);
}
return count;
}
O(logN) :
对数阶与指数阶相反,指数阶
为 “每轮分裂出两倍的情况” ,而对数阶
是 “每轮排除一半的情况” 。对数阶常出现于「二分法」、「分治」等算法中,体现着 “一分为二” 或 “一分为多” 的算法思想。
设循环次数为 m ,则输入数据大小 N 与 2 m呈线性关系,两边同时取 log2对数,则得到循环次数 m与 log2N呈线性关系,即时间复杂度为 O(logN)。
int algorithm(int N) {
int count = 0;
float i = N;
while (i > 1) {
i = i / 2;
count++;
}
return count;
}
朴素模式匹配算法
串的朴素模式匹配算法,主要思想是对主串(S)的每一个字符作为子串(T)的开头,与要匹配的字符串进行匹配。主串(S)的长度为n,要匹配的子串的长度为m,那么朴素模式匹配算法的最好时间复杂度
为Ω(1)(第一次匹配就成功),最坏时间复杂度
为O(n-m+1)*m),
平均情况
Θ(n+m)(根据等概率原则,平均是(n+m)/2次查找)。