leetcode第739题,原题如下:
一、首先想到的是O(n2)暴力法
对于每一个元素都向后遍历,直到找到第一个比当前元素大的位置,记录距离差。
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
l=len(T)
lst=[0]*l
for index in range(l):
for j in range(index+1,l):
if T[j]>T[index]:
lst[index]=j-index
break
return lst
超时,时间复杂度太高。
二、基于暴力法的改进,复杂度为O(nlogn)
读一遍列表,因为只有30-100这71个数字,为了方便可以分别设置101个列表,将每个元素的索引都对应在这个元素的列表里。
例如[41,42,42,44]对应的列表为[[]…[],[0],[1,2],[],[3],[]…[]];
(其中,[0]对应的下标为41,[1,2]对应的下标为42,[3]对应的下标为44。)
遍历温度表,以index=2的数字75为例,先到76对应的列表中找索引大于2的最小值p,使lst[index]=min(lst[index],p-index),找完76–101这26个数组中的最小距离,就是我们需要的距离。
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
l=len(T)
lst=[[] for _ in range(101)]
#为了后边min可以顺利起作用,把初值设为比最长距离30000还大的40000
ret=[40000]*l
for index in range(l):
lst[T[index]].append(index)
for index in range(l):
i=1
while 30<T[index]+i<101:
if not lst[T[index]+i]:
i+=1
continue
#二分找最小位置
t=lst[T[index]+i]
left,right=0,len(t)-1
loc=right
while left<=right:
mid=(left+right)//2
if t[mid]>index:
loc=mid
right=mid-1
else:
left=mid+1
#print(t[loc],loc)
if t[loc]>index:
ret[index]=min(ret[index],t[loc]-index)
i+=1
for index in range(len(ret)):
ret[index]=0if ret[index]==40000else ret[index]
return ret
时间复杂度仍较高,超时。
(笔者感觉这个复杂度也可以了,应该是代码水平不行所以超时)
三、使用栈,O(n)复杂度
这是笔者学习大神‘程序员吴师兄’的思路写的代码,原文链接,视频讲解非常清楚,膜拜辽。
思路是维护一个上小下大的单调栈。
栈初始值为元组(0,T[0])。
对于后面每一个元素new,如果他大于栈顶元素t,表明栈顶元素t遇到了第一个比t高的温度,则t出栈,将ret[t[0]]位置记录为index-t[0](即new和t之间的距离差)。
遍历至终点,没有遇到更大元素的位置仍为初始值0。
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
ret=[0]*len(T)
stack=[(0,T[0])]
for index in range(1,len(T)):
while stack and T[index]>stack[-1][1]:
t=stack.pop(-1)
ret[t[0]]=index-t[0]
stack.append((index,T[index]))
return ret