python 刷题篇(1)---- 时间复杂度和空间复杂度的分析

这是一个系列篇,主要是用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;
}

 

你可能感兴趣的:(leetcode刷题,python,算法)