单调栈
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,可以考虑用单调栈。
1.单调栈里存放的元素是什么?
单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。
2.单调栈里元素是递增呢? 还是递减呢?
从栈头到栈底的顺序,使用递增循序。因为只有递增的时候,加入一个元素i,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i
三种情况:T[i]小于栈顶,等于栈顶,大于栈顶
class Solution(object):
def dailyTemperatures(self, temperatures):
answer=[0]*len(temperatures)
stack=[0]
for i in range(1,len(temperatures)):
if temperatures[i]<=temperatures[stack[-1]]:
stack.append(i)
else:
while stack and temperatures[i]>temperatures[stack[-1]]:
answer[stack[-1]]=i-stack[-1]
stack.pop()
stack.append(i)
return answer
没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。
class Solution(object):
def nextGreaterElement(self, nums1, nums2):
res=[-1]*len(nums1)
stack=[0]
for i in range(1,len(nums2)):
if nums2[i]<=nums2[stack[-1]]:
stack.append(i)
else:
while stack and nums2[i]>nums2[stack[-1]]:
if nums2[stack[-1]] in nums1:
ind=nums1.index(nums2[stack[-1]])
res[ind]=nums2[i]
stack.pop()
stack.append(i)
return res
在遍历的过程中模拟走了两遍nums
class Solution(object):
def nextGreaterElements(self, nums):
res=[-1]*len(nums)
stack=[0]
for i in range(len(nums)*2):
while stack and nums[i%len(nums)]>nums[stack[-1]]:
res[stack[-1]]=nums[i%len(nums)]
stack.pop()
stack.append(i%len(nums))
return res
取栈顶元素,将栈顶元素弹出,这个就是凹槽的底部,也就是中间位置,下标记为mid,对应的高度为height[mid]。
此时的栈顶元素st.top(),就是凹槽的左边位置,下标为st.top(),对应的高度为height[st.top()]。
当前遍历的元素i,就是凹槽右边的位置,下标为i,对应的高度为height[i]。
class Solution(object):
def trap(self, height):
sum_=0
stack=[0]
for i in range(1,len(height)):
if height[i]<=height[stack[-1]]:
stack.append(i)
else:
while stack and height[i]>height[stack[-1]]:
mid=stack[-1]
stack.pop()
if stack:
h=min(height[stack[-1]],height[i])-height[mid]
w=i-stack[-1]-1
sum_+=h*w
stack.append(i)
return sum_
本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序
找每个柱子左右侧的第一个高度值小于该柱子的柱子
单调栈:栈顶到栈底:从大到小(每插入一个新的小数值时,都要弹出先前的大数值)
栈顶,栈顶的下一个元素,即将入栈的元素:这三个元素组成了最大面积的高度和宽度
class Solution(object):
def largestRectangleArea(self, heights):
heights.insert(0,0)
heights.append(0)
stack=[0]
res=0
for i in range(1,len(heights)):
if heights[i]>=heights[stack[-1]]:
stack.append(i)
else:
while stack and heights[i]<heights[stack[-1]]:
mid=stack[-1]
stack.pop()
if stack:
left=stack[-1]
right=i
w=right-left-1
h=heights[mid]
res=max(res,w*h)
stack.append(i)
return res
图论
回溯算法,其实就是dfs的过程
有向图搜索全路径问题。只能用深度搜索DFS/广度搜索BFS
class Solution(object):
def canVisitAllRooms(self, rooms):
self.visited=[False]*len(rooms)
self.dfs(0,rooms)
for i in range(len(self.visited)):
if self.visited[i]!=True:return False
return True
def dfs(self,key,rooms):
if self.visited[key]:return
self.visited[key]=True
keys=rooms[key]
for i in keys:
self.dfs(i,rooms)
无向图求最短路,广搜最为合适,广搜只要搜到了终点,那么一定是最短的路径。因为广搜就是以起点中心向四周扩散的搜索。
class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
from collections import deque
wordset=set(wordList)
if len(wordset)==0 or endWord not in wordset:return 0
mapp={beginWord:1}
que=deque([beginWord])
while que:
word=que.popleft()
path=mapp[word]
for i in range(len(word)):
word_list=list(word)
for j in range(26):
word_list[i]=chr(ord('a')+j)
newword=''.join(word_list)
if newword==endWord:
return path+1
if newword in wordset and newword not in mapp:
mapp[newword]=path+1
que.append(newword)
return 0
并查集
并查集主要解决集合问题,两个节点在不在一个集合,也可以将两个节点添加到一个集合中
模板
int n = 1005; // 节点数量3 到 1000
int father[1005];
// 并查集初始化
void init() {
for (int i = 0; i < n; ++i) {
father[i] = i;
}
}
// 并查集里寻根的过程
int find(int u) {
return u == father[u] ? u : father[u] = find(father[u]);
}
// 将v->u 这条边加入并查集
void join(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return ;
father[v] = u;
}
// 判断 u 和 v是否找到同一个根
bool same(int u, int v) {
u = find(u);
v = find(v);
return u == v;
}
从前向后遍历每一条边,边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,如果再加入这条边一定就出现环了。
class Solution(object):
def __init__(self):
n=1005
self.father=[i for i in range(n)]
def find(self,u):
if u==self.father[u]:return u
self.father[u]=self.find(self.father[u])
return self.father[u]
def join(self,u,v):
u=self.find(u)
v=self.find(v)
if u==v:return
self.father[v]=u
def same(self,u,v):
u=self.find(u)
v=self.find(v)
return u==v
def findRedundantConnection(self, edges):
self.__init__()
for i in range(len(edges)):
if self.same(edges[i][0],edges[i][1]):return edges[i]
else:self.join(edges[i][0],edges[i][1])
return []
并查集为什么可以判断 一个图是不是树呢?
因为如果两个点所在的边在添加图之前如果就可以在并查集里找到了相同的根,那么这条边添加上之后 这个图一定不是树了
模拟
class Solution(object):
def judgeCircle(self, moves):
x,y=0,0
for i in range(len(moves)):
if moves[i]=='U':y+=1
elif moves[i]=='D':y-=1
elif moves[i]=='R':x+=1
elif moves[i]=='L':x-=1
return x==0 and y==0
从后向前遍历,发现nums[j]>nums[i],进行交换,对i+1到数据结束的区间进行排序
class Solution(object):
def nextPermutation(self, nums):
lenght=len(nums)
for i in range(lenght-1,-1,-1):
for j in range(lenght-1,i,-1):
if nums[j]>nums[i]:
nums[i],nums[j]=nums[j],nums[i]
self.reverse(nums,i+1,lenght-1)
return nums
return self.reverse(nums,0,lenght-1)
def reverse(self,nums,l,r):
while l<r:
nums[l],nums[r]=nums[r],nums[l]
l+=1
r-=1
遍历每一个空格,遇到岛屿,计算其上下左右的情况,遇到水域或者出界的情况,就可以计算边了
class Solution(object):
def islandPerimeter(self, grid):
sum_=0
direction=[[0,1],[0,-1],[-1,0],[1,0]]
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j]==1:
for k in range(len(direction)):
x=i+direction[k][0]
y=j+direction[k][1]
if x<0 or x>=len(grid) or y<0 or y>=len(grid[0]) or grid[x][y]==0:
sum_+=1
return sum_
位运算
&位运算符
class Solution(object):
def sortByBits(self, arr):
arr.sort(key=lambda num:(self.countbit(num),num))
return arr
def countbit(self,num):
count=0
while num:
num&=num-1
count+=1
return count