本文是覃超老师的《算法训练营》的学习笔记,此笔记的内容包含了学习后的个人记录、个人总结、理解和思想。从而更好的学习算法。
学习任何一门知识的时候,我们需要分析清楚这门知识的核心是什么,从而在这个核心中我们可以得到什么。如果我们是盲目的吸收知识,其实很多知识我们都是在目前场景、工作、生活中无法使用的。也是因为学习之后无法运用,所以我们很快就会遗忘,或者是在学习的过程中很容易就会放弃。
在一生的学习的过程中,发现学习我们急需使用或者能给我们及时带来价值的知识,我们会学的更加牢固,更加能坚持学习。
学习《数据结构与算法》这门知识的核心是什么?又能得到什么呢?
这篇笔记记录了算法的核心时间和空间复杂度
,《数据结构与算法》都是围绕着这个核心开展的。它的存在也是为了解决我们在编程的过程中性能问题,同时也让我们有更高级的思维和思路,写出更优质的程序。
O (1) - 常数复杂度
let n = 1000;
console.log("Hello - your input is: " + n)
O (N) - 线性复杂度
for (let i = 1; i <= n; i++) {
console.log("Hello world - your input is: " + i)
}
O (N^2)
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {
console.log("Hello world - your input is: " + i + " and " + j)
}
}
那如果我们不是嵌套两层
for
循环,是把两个循环分开来存放呢?这种方式时间复杂度是?
for (let i = 1; i <= n; i++) {
console.log("Hello world - your i input is: " + i)
}
for (let j = 1; j <= n; j++) {
console.log("Hello world - your j input is: " + j)
}
很多小伙伴应该猜到了,就是2* n次的复杂度,那就是O(2n)。其实还是O(n)
的时间复杂度。
O(log(n))
for (let i = 1; i < n; i = i * 2) {
console.log("Hello world - your input is: " + i);
}
O(k^n)
// Fibonacci递归
function fib (n) {
if (n <= 2) return n;
return fib(n-1) + fib(n-2);
}
y
轴是Operations
就是操作复杂度的指数;x
轴是Elements
就是n
我们的循环次数 ;n
比较小的时候,复杂度是相对稳定的;n
越来越大时,Big-O复杂度就会急速飙升;所以在我们写程序的时候,如果能把时间和空间复杂度从
O(n^2)
降到O(n)
或者O(1)
后,我们得到的优化收益是非常高的!
我们用个例子就可以看到如何在编程中降低复杂度:
计算:1 + 2 + 3 + ... + n
方法一:循环1到n然后累加 (时间复杂度 O(n)
)
let sum = 0
for (let i = 1; i < n; i++) {
sum += i
}
console.log(sum)
方法二:求和公式 sum = n(n+1)/2
(时间复杂度 O(1)
)
let sum = n * (n + 1) / 2
console.log(sum)
注意:
确认题目
,确保一切的条件和题目的理解无误;想出所有可能
的解决方案;比较每个方法
的时间和空间复杂度;找出最优
的解决方案(时间最快,内存使用最少)斐波那契(Fibonacci)例子
公式:F(n) = F(n - 1) + F(n - 2)
我们可以直接使用递归来解题:
function fib(n) {
if (n <= 2) return n
return fib(n - 1) + fib(n - 2)
}
fib
斐波那契函数中是一个递归
;n
值时,都会循环递归fib
方法来一层一层往下计算;n
小于2,返回最后的n
值;那针对这个递归,我们怎么计算它的时间复杂度呢?
复杂度
,首先我们要知道具体在这个函数中程序做了什么;n
为6
,那就是运行fib(6)
6
被传入这个方法,然后返回的就是fib(5)
+fib(4)
,这时fib(5)
和fib(4)
就会再进入fib
函数,这里就分开了两个分支了。以此类推我们就会出现以下一个树状过程:fib(6)
展开为fib(5)
+fib(4)
,然后fib(5)
和fib(4)
又展开了两个。fibonacci
的执行次数就是一个指数级 - O(2^n)
fib(3)
、fib(4)
等等,都被重复计算了多次,所以这个计算的复杂度高达2的6次方;任何一个分治或者递归函数都可以通过这个定理来算出它们的时间复杂度。这个定理里面有4种最常用的,只要记住这4种就可以了。
算法 (Algorithem) | 时间复杂度 (Run time) |
---|---|
二分查找 (Binary search) | O(log n) |
二叉树遍历 (Binary tree traversal) | O(n) |
排序二维矩阵 (Optimal sorted matrix search) | O(n) |
归并排序 (Merge sort) | O(n log n) |
O(n)
,无论是前序、中序或者后序每一个节点都会访问一次,并且仅访问一次;O(n)
的线性时间复杂度;O(n)
, 这里的n
就是图里面的节点总数;O(n)
的。(n
指的是搜索空间里面的节点总数)O(log n)
O(n)
O(n)
O(n)
O(log n)
我是三钻,一个在技术银河中等你们一起来终身漂泊学习。点赞是力量,关注是认可,评论是关爱!下期再见 ?!