时间复杂度和空间复杂度
衡量算法的执行时间和空间
1. 引例
1.1 引例1
下面函数中,假设数组有n个元素,下面程序执行了多少次
function sum(A){
let sum = 0 // 执行1次
for (let i = 0; i < A.length; i++) { // i = 0执行了1次,i < A.length执行了n+1次,i++执行了n次
sum += A[i] // 执行了n次
}
return sum // 执行了1次
}
所以以上代码执行次数为3n+4次,即
T = 3n + 4
时间复杂度记作O(n)
1.2 引例2
下面函数中,n*n的二维数组求和,下面程序执行了多少次
function sum(A){
let sum = 0 // 执行1次
for (let i = 0; i < A.length; i++) { // i = 0执行了1次,i < A.length执行了n+1次,i++执行了n次
for (let j = 0; j < A[i].length; j++) { // j = 0执行了n次,j < A.length执行了n(n+1)次,j++执行了n*n次
sum += A[i][j] // 执行了n*n次
}
}
return sum // 执行了1次
}
所以以上代码执行次数为3n^2 + 4n + 4次,即
T = 3n^2 + 4n + 4
时间复杂度记作O(n^2)
1.3 引例总结
- 随着规模的增长O(n^2)的算法比O(n)的算法增长更快
- 在 T = an^2 + bn + c的算法中,n^2起决定作用
- 通常的,算法在更大输入集合的表现更有意义
- nnn的三维数组求和,程序执行的次数是 T = an^3 + bn^2 + cn + d,时间复杂度记作O(n^3)
- 以此类推,x维数组求和,时间复杂度O(n^x)
- 我们其实不用去算时间复杂度,只要找到关键之处,就能看出来,比如以下求出nm的二维数组求和,时间复杂度是O(nm),因为值需要看最核心的sum+=A[i][j]就可以了。
function sum(A){
let sum = 0
for (let i = 0; i < A.length; i++) {
for (let j = 0; j < A[i].length; j++) {
sum += A[i][j] // 执行了n*m次
}
}
return sum
}
- 所有执行时间是一个常数的,即 T = C,那么时间复杂度为O(1)
2. 时间复杂度
时间复杂度用于衡量执行时间随着输入规模增加而增长的关系,是一种对算法的分类,并不是算法的具体执行时间
2.1 举例
2.1.1 举例1
求出n*m的二维数组求和,时间复杂度是多少
function sum(A){
let sum = 0
for (let i = 0; i < A.length; i++) {
for (let j = 0; j < A[i].length; j++) {
sum += A[i][j] // 执行了n*m次
}
}
return sum
}
只要找到最核心的代码,也就是次数最高的代码,根本不需要管前面的系数,所以这里的时间复杂度为O(m*n)
2.1.2 举例2
长度为n的数组A和长度为m的数组B合并,时间复杂度是多少?
function merge(A, B) {
let r = []
for (let i = 0; i < A.length; i ++) {
r.push(A[i]); // 执行了n次
}
for (let i = 0; i < A.length; i ++) {
r.push(B[i]); // 执行了m次
}
return r
}
时间复杂度为O(n + m)
2.1.3 举例3
对规模为n的数组第0项和第n项求和,时间复杂度是多少
function sum_head_tail(A) {
return A[0] + A[A.length - 1]
}
对于这类时间是一个常数的,即 T = C,我们记作时间复杂度为O(1)
2.1.4 举例4
对规模为n的数组,加和约一半元素,时间复杂度是多少?
function sum(A) {
let sum = 0
for (let i = 0; i < A.length/2; i++) {
sum += A[i] // 执行了n/2次
}
return sum
}
上面的sum += A[i]执行了n/2次,那么这个时间复杂度不是O(n/2),只记作O(n),不用管系数
3. 空间复杂度
空间复杂度是指算法用了多少额外的空间
每天下班学习到12点,一定会有所收获的,加油!未完待续!