这是一个系列篇,主要是用python刷题,适用于喜欢用python刷题的小伙伴一起交流和讨论,之前作者基于java、c\c++都刷过,这次使用python更加系统的根据校招高频题进行分析。
首先分析一下做题需要注意的重点内容:
•
重点在理解不在数量,经典题多做,做到一看到原题能直接
AC
。
•
互联网公司大多考的是
Leetcode
上剑指
offer
、
hot
100
的题,但不是绝对,大多看面试官的算法水平。个人感觉阿里、腾讯面的算法都在中等偏简单的水平,腾讯重在性能、最优解,题不难。
•
自己做出来之后并没有结束,要看题解
最优解
。
其次是高频模块分析:
•
深度优先搜索(
DFS
)
•
广度优先搜索(
BFS
)
•
递归、记忆化搜索
•
动态规划(
DP
)
•
二叉树相关问题
•
链表相关问题
•
…
时间复杂度分析:(不得不承认,时间复杂度和空间复杂度是面试官考察的重点,通常在做完一道算法题之后就会问这个问题。所以需要重点掌握)
•
和数据规模
n
有关,看循环嵌套情况,最好每道题都分析一下对应的时间复杂度和空间复杂度。
•
最差的时间复杂度是
O(N^2
)
,
O(N^3
)···
•
更优解就是
减少时间复杂度
,但是通常会
增加空间复杂度。
这就是俗称的以空间换时间的问题。
for(int i = 0; i < n; i++) {
} //O(m)时间复杂度
for(int i = 0; i < m; i++) {
for(int i = 0; i < n; i++) {
}
} //O(mn)时间复杂度
func(int val, int a[], int start, int end) {
if(start > end) {
return false;
}
int mid = (start + end) / 2;
if(val == a[mid]) {
return true;
} else {
if(val < a[mid]) {
return func(val, a, start, mid - 1);
} else {
return func(val, a, mid + 1, end);
}
}
return false;
} //最常见的二分法是O(log(n))时间复杂度
空间复杂度分析:
•
和数据规模
n
有关。
•
在一些题中会指明比如常数级空间复杂度
O(1)
,这是指的是不能重新开数组或者
hashmap
对数据进行中间存储。只能用题中给出的比如数组进行中间数值的存储,这样也就会增加题目难度,因为很有可能在数据处理过程中,需要前一个数据作为计算的一部分,但是前一个数据在上一次运算中重新赋值,这样就会造成数据的错误。
•
比如: 使用
a[i] = a[i - 1] + 5
策略将
a
数组数值进行更新。要求空间复杂度
O(1)
。
a=
{1,3,5,2}。下面是正确和错误结果的分析和例子。
//空间O(1),时间O(n),错误返回a={1, 6, 11, 16}
for(int i = 1; i < m; i++) {
a[i] = a[i] + 5;
}
//空间O(n),时间O(n),正确返回a = {1, 6, 8, 10}
int b[m];
b[0] = a[0];
for(int i = 1; i < m; i++) {
b[i] = a[i];
a[i] = b[i - 1] + 5;
}
//空间O(1),时间O(n),正确返回a = {1, 6, 8, 10}
int tmp = a[0];
for(int i = 1; i < m; i++) {
int tmp1=a[i];
a[i] = tmp+ 5;
tmp = tmp1;
}
//空间O(1),时间O(n),正确返回a = {1, 6, 8, 10}
for(int i = m – 1; i > 1; i--) {
a[i] =a[i - 1] + 5;
}
复杂度总结:(刷题的基础就是先要掌握时间复杂度和空间复杂度的分析,划重点)
•
时间复杂度和空间复杂度往往是相互影响的。
•
当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间;
•
当追求一个较好的空间复杂度时,可能会使时间复杂度的性能变差,即可能导致占用较长的运行时间。
•
因此在实际开发场景是时间和空间复杂度的折衷,实现最合理的性能结果。
青蛙跳台阶问题:是经典的可以用空间换时间的问题
1)题解(1)单纯的通过递归进行计算,会显示超时,因为在每一个状态都会额外的多计算其子状态结果,然后才能得到当前状态结果。
2)题解(2)则是使用空间换时间,通过存储每一个状态的信息,使得在下一次到达这个状态时直接返回存储的该节点状态即可,无需进行额外的计算操作。这也就是俗称的以记忆化搜索操作。
#(1)超过时间限制,时间复杂度O(𝑛!),空间复杂度O(1) 报错,超时错误
int numWays(int n){
if(n == 0 || n == 1) {
return 1;
}
return numWays(n - 1) + numWays(n - 2);
}
#(2)空间换时间 空间复杂度O(n),时间复杂度O(n)
int num[101] = {0};
int numWays(int n){
if(n == 0 || n == 1) {
return 1;
}
if(num[n - 1] == 0) {
num[n - 1] = numWays(n - 1) % 1000000007;
}
if(num[n - 2] == 0) {
num[n - 2] = numWays(n - 2) % 1000000007;
}
return (num[n - 1] + num[n - 2]) % 1000000007;
}