做了不少LeetCode题了,发现总是时间花费多,当然一部分原因肯定跟服务器负载有关,但是还有一个重要原因:
不了解list、set等相关操作的时间复杂度!
去面试时也写了垃圾代码,别人一问Insert复杂度多少?你这个代码复杂度是O(n)吗?一下原形毕露。
比如,定义了一个list,使用insert操作时间复杂度为O(n),虽然显得代码简单,但是实际上耗费时间很多
def wrong(self,listIn):
# 错误示范,O(n)
listIn.insert(len(listIn)+1,"abc")
def right(self,listIn):
# O(1)的正确方法
listIn.append("abc")
这个实例不好,不能说明问题,谁能用append去用insert啊,只是想说复杂度很不一样,有时候同一个问题,换一种思路(或者说改变部分数据结构)时间消耗迅速减少!后文给一个好点的例子
总结下常用的时间复杂度:
list | O(n) | pop(i),insert(i,item),contains (in),reverse() |
O(1) | pop(),append(item) | |
单独拿一行来说明,在执行in操作时: 如:if "a" in list1: #判断"a"是否在list1里,复杂度O(n) if "a" in set1:#判断“a"是否在set1中,复杂度O(1) in操作在list中复杂度线性,在set和dict数据结构中复杂度为O(1),所以如果发现list操作时代码效率低,不妨改成set,会快很多 |
比如pop(-1)和pop()在运行是一致的,但是pop(i)的最坏情况是O(n)所以归为O(n)
特别地,sort()方法是O(n log n)
来一道具体的题体验一下,LeetCode第150题--根据逆波兰表示法,求表达式的值。有效的运算符包括 +
, -
, *
, /
。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
- 整数除法只保留整数部分。
- 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: ((2 + 1) * 3) = 9
示例 2:
输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: (4 + (13 / 5)) = 6
示例 3:
输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
输出: 22
解释:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
简单点说,我们平常做的是中序表达,比如1+2,符号在中间,换成后序表达就是逆波兰,12+
以下是代码,后序表达很简单,不说了。主要是我的思路是在原list堆栈上进行修改,别人是新建一个栈进行存取,方法出现了差异,主要在我的代码需要使用pop(i),而别人的只需要pop()+append(),就出现时间复杂度上的差异,虽然这道题提交时时间不会差异太大,但如果测试集很大的话就会出现很大差异了!
# 我做的
def evalRPN(self, tokens):
stack = tokens
i = 0
while i < len(stack):
if stack[i] == '+':
stack [i-2] = int(stack[i-2]) + int(stack[i-1])
stack.pop(i-1) #多次Pop(i)操作,时间复杂度高
stack.pop(i-1)
i = i-2
elif stack[i] == '-':
stack[i - 2] = int(stack[i - 2]) - int(stack[i - 1])
stack.pop(i - 1)
stack.pop(i - 1)
i = i - 2
elif stack[i] == '*':
stack[i - 2] = int(stack[i - 2]) * int(stack[i - 1])
stack.pop(i - 1)
stack.pop(i-1)
i = i - 2
elif stack[i] == '/':
stack[i - 2] = int(int(stack[i - 2]) / int(stack[i - 1]))
stack.pop(i - 1)
stack.pop(i-1)
i = i - 2
else:
i+=1
return stack[0]
# 别人的
stack = []
for i in tokens:
try:
i = int(i)
except:
# print("--",stack)
s1 = stack.pop() #稍微改变了下思路,就只使用pop()了
s2 = stack.pop()
if i == "*":a = s1*s2
elif i == "/":a = int(s2/s1)
elif i == "+":a = s1+s2
elif i == "-":a = s2-s1
stack.append(a)
else:
stack.append(i)
return int(stack[0])
仅以此文警醒多用pop,append少用insert,如果涉及到in,不妨转换为set