堆栈算法
再讲算法之前先说一下堆与栈的区别
两个栈实现队列
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if self.stack2 == []:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
包含min函数的栈
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack = []
self.assit = []
def push(self, node):
# write code here
min_data = self.min()
if min_data > node or len(self.stack)==0:
self.stack.append(node)
self.assit.append(node)
else:
self.stack.append(node)
def pop(self):
# write code here
if self.stack:
if self.stack[-1] == self.assit[-1]:
self.stack.pop()
self.assit.pop()
else:
self.stack.pop()
def top(self):
# write code here
if self.stack>0:
return self.stack[-1]
def min(self):
# write code here
if self.assit:
return self.assit[-1]
栈的压入弹出
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
stack = []
while popV:
if stack and stack[-1] == popV[0]:
popV.pop(0)
stack.pop()
elif pushV :
stack.append(pushV.pop(0))
else:
return False
return True
滑动窗口的最大值(queue中保存的是滑动窗口最大值的下标)
# -*- coding:utf-8 -*-
class Solution:
def maxInWindows(self, num, size):
# write code here
queue,res,i = [],[],0
while size>0 and i<len(num):
if len(queue)>0 and i-size+1>queue[0]:
queue.pop(0)
while len(queue)>0 and num[queue[-1]] < num[i]:
queue.pop()
queue.append(i)
if i>=size-1:
res.append(num[queue[0]])
i +=1
return res
电话号码的字母组合:
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
d = [" ","*","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
res = ['']
for i in digits:
letter = d[ord(i)-48]
size = len(res)
for _ in range(size):
tmp = res.pop(0)
for j in letter:
res.append(tmp+j)
return res
有效的括号:
class Solution:
def isValid(self, s: str) -> bool:
if not s:
return True
dict = {'(':')','[':']','{':'}','?':'?'}
stack = ['?']
for i in s:
if i in dict:
stack.append(i)
elif dict[stack.pop()] !=i :
return False
return len(stack)==1
接雨水:
class Solution:
def trap(self, height: List[int]) -> int:
length = len(height)
if length < 3: return 0
res, idx = 0, 0
stack = []
while idx < length:
while len(stack) > 0 and height[idx] > height[stack[-1]]:
top = stack.pop() # index of the last element in the stack
if len(stack) == 0:
break
h = min(height[stack[-1]], height[idx]) - height[top]
dist = idx - stack[-1] - 1
res += (dist * h)
stack.append(idx)
idx += 1
return res
简化路径
class Solution:
def simplifyPath(self, path: str) -> str:
stack = []
path = path.split('/')
for i in path:
if i == '..':
if stack:
stack.pop()
elif i and i !='.':
stack.append(i)
return '/'+'/'.join(stack)
柱形图中最大的矩形
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
n = len(heights)
res = 0
stack = [0]
height = [0] + heights + [0]
for i in range(1,n+2):
while stack and height[i]<height[stack[-1]]:
h = height[stack.pop()]
if not stack:
break
w = i - stack[-1] -1
res = max(res,h*w)
stack.append(i)
return res
逆波兰表达式求值
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
f = ['+','-','*','/']
stack = []
res = 0
if len(tokens)==1:
return int(tokens[0])
for i in tokens:
if i not in f:
stack.append(i)
elif i == '+':
right = int(stack.pop())
left = int(stack.pop())
res = left + right
stack.append(res)
elif i == '-':
right = int(stack.pop())
left = int(stack.pop())
res = left - right
stack.append(res)
elif i == '*':
right = int(stack.pop())
left = int(stack.pop())
res = left * right
stack.append(res)
else:
right = int(stack.pop())
left = int(stack.pop())
res = left / right
stack.append(res)
return int(res)
最小栈
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
def push(self, x: int) -> None:
return self.stack.append(x)
def pop(self) -> None:
return self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return min(self.stack)
数组中第K个最大的元素
#最大堆
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
把最大的元素放在数组的头部
def adjust_heap(idx, max_len):
left = 2 * idx + 1
right = 2 * idx + 2
max_loc = idx
if left < max_len and nums[max_loc] < nums[left]:
max_loc = left
if right < max_len and nums[max_loc] < nums[right]:
max_loc = right
if max_loc != idx:
nums[idx], nums[max_loc] = nums[max_loc], nums[idx]
adjust_heap(max_loc, max_len)
# 建堆
n = len(nums)
for i in range(n // 2 - 1, -1, -1):
adjust_heap(i, n)
#print(nums)
res = None
for i in range(1, k + 1):
#print(nums)
res = nums[0]
nums[0], nums[-i] = nums[-i], nums[0]
adjust_heap(0, n - i)
return res
#快排
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def partition(left, right):
pivot = nums[left]
l = left + 1
r = right
while l <= r:
if nums[l] < pivot and nums[r] > pivot:
nums[l], nums[r] = nums[r], nums[l]
if nums[l] >= pivot:
l += 1
if nums[r] <= pivot:
r -= 1
nums[r], nums[left] = nums[left], nums[r]
return r
left = 0
right = len(nums) - 1
while 1:
idx = partition(left, right)
if idx == k - 1:
return nums[idx]
if idx < k - 1:
left = idx + 1
if idx > k - 1:
right = idx - 1
基本计数器
class Solution:
def calculate(self, s: str) -> int:
stack = []
# 记录数字的符号, 因为题目说没有负数,说明第一个为正数,设为1
sign = 1
# 数字
num = 0
# 结果
res = 0
for c in s:
if c.isdigit():
num = num * 10 + int(c)
elif c == "+":
res += sign * num
# 为下一次做准备
num = 0
sign = 1
elif c == "-":
res += sign * num
# 为下一次做准备
num = 0
sign = -1
elif c == "(":
stack.append(res)
stack.append(sign)
sign = 1
res = 0
elif c == ")":
res += sign * num
num = 0
res = stack.pop() * res + stack.pop()
res += sign * num
return res
删除无效的括号
class Solution:
def removeInvalidParentheses(self, s:str) -> List[str]:
def isValid(s:str)->bool:
cnt = 0
for c in s:
if c == "(": cnt += 1
elif c == ")": cnt -= 1
if cnt < 0: return False # 只用中途cnt出现了负值,你就要终止循环,已经出现非法字符了
return cnt == 0
# BFS
level = {s} # 用set避免重复
while True:
valid = list(filter(isValid, level)) # 所有合法字符都筛选出来
if valid: return valid # 如果当前valid是非空的,说明已经有合法的产生了
# 下一层level
next_level = set()
for item in level:
for i in range(len(item)):
if item[i] in "()": # 如果item[i]这个char是个括号就删了,如果不是括号就留着
next_level.add(item[:i]+item[i+1:])
level = next_level
计算右侧小于当前元素的个数
import bisect
class Solution:
def countSmaller(self, nums: List[int]) -> List[int]:
re_nums = nums[::-1]
bi_arr = []
res = []
for _ in re_nums:
#插入_数字时在数组中的位置
pos = bisect.bisect_left(bi_arr, _)
res.append(pos)
#插入_
bisect.insort_left(bi_arr, _)
return res[::-1]
根据身高重建队列
class Solution:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
people.sort(key = lambda x: (-x[0], x[1]))
output = []
for p in people:
output.insert(p[1], p)
return output
下一个更大的元素
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
stack, hashmap = list(), dict()
for i in nums2:
while len(stack) != 0 and stack[-1] < i:
hashmap[stack.pop()] = i
stack.append(i)
return [hashmap.get(i,-1) for i in nums1]
每日温度
import collections
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
n = len(T)
ans = [0]*n
stack = []
for i in range(n-1,-1,-1):
while stack and T[i]>=T[stack[-1]]:
stack.pop()
#stack里面保存的永远都是从大到小的温度的index
#stack[-1]是T[i]<的最近的index
#因为是倒序遍历,所以不用考虑stack.pop()出的温度,
# 因为他的index值大于stack[-1]的index,但是温度却小于stack[-1]的温度,
# 通俗的说就是性价比较低
if stack:
ans[i] = stack[-1]-i
stack.append(i)
return ans