Python算法题笔记
这是本人在学Python和算法题时做的笔记,包含一些Python的典型写法,有用的轮子调用,希望对大家有帮助。
分为三个部分,Python笔记,算法,经典题目,其中Python笔记又包含基本用法,基本的轮子,数据结构。
算法包括Dijkstra,拓扑排序,二分法,回溯。(具体看目录好了)
文中的题目一般来自力扣,数字为题号。
其实本文最初的作用是在力扣周赛时为了节省时间积累的Pythonic写法和各种数据结构的api,算法的模板,以及经典的题目。
推荐在力扣做周赛的同学关注灵茶山艾府的题解,有各种Python的神奇操作和巧妙的解题思路。
以及入门某算法/数据结构时学习yukiyama的教程,如二分查找从入门到入睡。
其中某些解法中有“mine”的标记,是本人能想到的最朴素解法,只是一种补充(不必要的之后再删除)。
文章目录
Python笔记
基本用法
单词拼写
enumerate
sorted(lis,key=lambda x:f(x),reverse=True)
lis.extend
float('inf')
sys.setrecursionlimit(100000)
from bisect import bisect_left
from itertools import product,accumulate,permutations,combinations
from collections import defaultdict,Counter
from string import ascii_lowercase,ascii_uppercase
from typing import List
@cache # @lru_cache(None)
输入列表(空格隔开元素)
list(map(int,input().split()))
输出列表(空格隔开元素),解包
>>> a=[1,2,3]
>>> print(a)
[1, 2, 3]
>>> print(*a)
1 2 3
翻转序列
lis[::-1]
二进制、十六进制
bin(9) # '0b1001'
hex(31) # '0x1f'
int('11',2) # 3
int('11',16) # 17
int('11',7) # 8
ord(ch) & 15 相当于 ord(ch) - ord('0'),也就是 int(ch)
ord('0') #48
位运算
x += x & -x # 最低的 1 变成 0
x &= x - 1 # 最低的 1 变成 0
x |= x + 1 # 最低的 0 变成 1
7.bit_length() #SyntaxError: invalid syntax
7 .bit_length() #3
(7).bit_length() #3
bin(n).count("1") #位1的个数
解析数学表达式
eval('2+3*4+5*(6+7)') # 79
Python枚举(enumerate):
for counter, value in enumerate(some_list):
print(counter, value)
Python数组按关键词递减排序
arr=['qw','ert','y']
arr=sorted(arr,key=lambda x:len(x),reverse=True)
cnt={'Alice':5,'userTwo':2,'Bob':5}
max(cnt, key = lambda k:(cnt[k], k))
#'Bob' #6084.最多单词数的发件人
Python中函数定义中自变量类型为列表
from typing import List
class Solution:
def myFun(self, nums: List[int], target: int) -> int:
pass
Python上取整
#ceil(x)函数是向上取整,即取大于等于x的最接近整数。
UP(A/B) = int((A+B-1)/B)
((a-1)//b + 1)
列表追加列表
nums.extend([0, int(2e9) + 1])
all,any
>>> all([1,0,2])
False
>>> any([1,0,2])
True
>>> all([])
True
>>> any([])
False
循环使用for … else 语句
lst = [3, 6, 3, 6, 9, 10, 20]
tag = True
count = 0
for item in lst:
if item % 2 == 0:
count += 1
if count > 3:
break
else:
tag = False
print(tag)
zip, dict
>>> list(zip([1,2,3],[4,5,6,7]))
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(*zip([1,2,3],[4,5,6,7])))
[(1, 2, 3), (4, 5, 6)]
>>> d=dict(zip([1,2,3],[4,5,6,7]))
>>> d
{1: 4, 2: 5, 3: 6}
>>> d.keys()
dict_keys([1, 2, 3])
>>> d.values()
dict_values([4, 5, 6])
>>> d.items()
dict_items([(1, 4), (2, 5), (3, 6)])
无穷大
float('inf')
字母
{chr(i):i-ord("a") for i in range(ord("a"),ord("z")+1)}
# {'a':0,'b':1,'c':2,'d':3,'e':4,'f':5,'g':6,'h':7,'i':8,'j':9,'k':10,'l':11,'m':12,'n':13,'o':14,'p':15,'q':16,'r':17,'s':18,'t':19,'u':20,'v':21,'w':22,'x':23,'y':24,'z':25}
缓存
@lru_cache #有限制
@lru_cache(None)
@cache #dfs.cache_clear()
python递归深度调整
import sys
sys.setrecursionlimit(100000)
如果您经常需要更改递归限制(例如在解决编程难题时),您可以像这样定义一个简单的上下文管理器:
import sys
class recursionlimit:
def __init__(self, limit):
self.limit = limit
def __enter__(self):
self.old_limit = sys.getrecursionlimit()
sys.setrecursionlimit(self.limit)
def __exit__(self, type, value, tb):
sys.setrecursionlimit(self.old_limit)
然后要调用具有自定义限制的函数,您可以执行以下操作:
with recursionlimit(1500):
print(fib(1000, 0))
从with
语句主体退出时,递归限制将恢复为默认值。
轮子
factorial阶乘
import math
math.factorial(5) # 120
bisect二分
import bisect
arr = [1, 2, 3, 5]
#ind= [0, 1, 2, 3, 4, 5]
ar2 = [1, 2, 3, 4, 4, 5]
print(bisect.bisect_left(arr, 4)) # 3
print(bisect.bisect_right(arr, 4)) # 3
# print(bisect.bisect(arr, 4)) # 3
print(bisect.bisect_left(ar2, 4)) # 3
print(bisect.bisect_right(ar2, 4)) # 5
# print(bisect.bisect(ar2, 4)) # 5
itertools,product笛卡尔积,排列组合
import itertools
for a in itertools.product([0,1],repeat=12)
# a=(0, 0, 0)等
list(itertools.permutations('abc',2)) # 缺少数时默认为长度
# [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
list(itertools.combinations('1234',2)) # 缺少数时报错
# [('1', '2'), ('1', '3'), ('1', '4'), ('2', '3'), ('2', '4'), ('3', '4')]
# groupby(iterable,key=None) 可以把相邻元素按照 key 函数分组,并返回相应的 key 和 groupby,如果key函数为 None,则只有相同的元素才能放在一组。
for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):
print(key,list(group))
# A ['A', 'a', 'a']
# B ['B', 'B', 'b']
# C ['c', 'C']
# A ['A', 'A', 'a']
defaultdict 字典提供默认值
>>> from collections import defaultdict
>>> d=defaultdict(int)
>>> d # defaultdict(<class 'int'>, {})
>>> d['q'] # 0
>>> d # defaultdict(<class 'int'>, {'q': 0})
>>> int() # 0
>>> list() # []
>>> set() # set()
>>> tuple() # ()
>>> str() # ''
>>> (lambda:0)() # 0
>>> d2=defaultdict(lambda:0)
>>> d2['q'] # 0
dict方法:__missing__
class myDict(dict):
def __missing__(self, key):
self[key] = key-1
return key+1
>>> d=myDict()
>>> d[1] # 2
>>> d # {1: 0}
>>> d[1] # 0
Counter 计数
>>> from collections import Counter
>>> c=Counter([1,2,1,3,2,4])
>>> c # Counter({1: 2, 2: 2, 3: 1, 4: 1})
>>> c[5] # 0
>>> c.items()
dict_items([(1, 2), (2, 2), (3, 1), (4, 1)])
>>> list(c.items())
[(1, 2), (2, 2), (3, 1), (4, 1)]
2190.数组中紧跟 key 之后出现最频繁的数字
by shikata-akiko-fans 我爱志方小姐
class Solution:
def mostFrequent(self, nums: List[int], key: int) -> int:
n = len(nums)
counter = Counter()
for i in range(0, n - 1):
if nums[i] == key:
counter[nums[i + 1]] += 1
return counter.most_common(1)[0][0]
Python中的Counter.most_common()方法_AI算法工程师YC的博客-CSDN博客_most_common() https://blog.csdn.net/qq_36134437/article/details/103245281
sum(c.values()) # 所有计数的总数
c.clear() # 重置Counter对象,注意不是删除
list(c) # 将c中的键转为列表
set(c) # 将c中的键转为set
dict(c) # 将c中的键值对转为字典
c.items() # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1] # 取出计数最少的n-1个元素
c += Counter() # 移除0和负值
top_three = word_counts.most_common(3)
print(top_three)
# Outputs [('eyes', 8), ('the', 5), ('look', 4)]
accumulate 累积
创建一个迭代器,返回累积汇总值或其他双目运算函数的累积结果值(通过可选的 func 参数指定)。
>>> import itertools
>>> itertools.accumulate([1,2,3,4,5])
<itertools.accumulate object at 0x0000013A2B175C80>
>>> list(itertools.accumulate([1,2,3,4,5]))
[1, 3, 6, 10, 15]
>>> list(itertools.accumulate([1,2,3,4,5],initial=100))
[100, 101, 103, 106, 110, 115]
>>> list(itertools.accumulate([1,2,3,4,5],lambda x,y:x*y))
[1, 2, 6, 24, 120]
>>> list(itertools.accumulate([3, 4, 6, 2, 1, 9, 0, 7, 5, 8], max))
[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]
字符串string
>>> s='aBcDe,qwERtY'
>>> s.upper()
'ABCDE,QWERTY'
>>> s.lower()
'abcde,qwerty'
>>> s.swapcase()
'AbCdE,QWerTy'
>>> s.title() #所有单词的首字母大写,其他全部小写
'Abcde,Qwerty'
>>> s.capitalize() #首字母大写,其他小写
'Abcde,qwerty'
>>> s="qwertyqwerty"
>>> s.find("qwe")
0
>>> s.rfind("qwe")
6
>>>
>>> s.find("asd")
-1
>>> s.index("asd")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> import string
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
子集
def get_sub_set(nums):
sub_sets = [[]]
for x in nums:
sub_sets.extend([item + [x] for item in sub_sets])
return sub_sets
def powlist(s):
r=[[]]
for e in s:
r+=[x+[e] for x in r]
return r
排列
下一个排列
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
n=len(nums)
i=n-2
while i>=0 and nums[i]>=nums[i+1]:
i-=1
if i>=0:
left,right=i+1,n-1
while left<right:
m=(left+right+1)//2
if nums[m]<=nums[i]:
right=m-1
else:
left=m
nums[i],nums[right]=nums[right],nums[i]
i,j=i+1,n-1
while i<j:
nums[i],nums[j]=nums[j],nums[i]
i+=1
j-=1
return
全排列
class Solution:#调包
def permute(self, nums: List[int]) -> List[List[int]]:
return list(itertools.permutations(nums))
class Solution:#官方,无重复
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
def backtrack(first = 0):
# 所有数都填完了
if first == n:
res.append(nums[:])
for i in range(first, n):
# 动态维护数组
nums[first], nums[i] = nums[i], nums[first]
# 继续递归填下一个数
backtrack(first + 1)
# 撤销操作
nums[first], nums[i] = nums[i], nums[first]
n = len(nums)
res = []
backtrack()
return res
class Solution:#考虑重复情况
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
ans=[]
p=[]
vis=[0]*len(nums)
n=len(nums)
nums.sort()
def generate(first=0):
if first==n:
ans.append(p[:])
for i in range(n):
if vis[i] or i>0 and nums[i]==nums[i-1] and vis[i-1]==0:
continue
p.append(nums[i])
vis[i]=1
generate(first+1)
vis[i]=0
p.pop()
generate()
return ans
数据结构
堆
api
代码,来自 heapq — 堆队列算法 — Python 3.10.3 文档 https://docs.python.org/zh-cn/3/library/heapq.html
heapq.heappush(heap, item)
将 item 的值加入 heap 中,保持堆的不变性。
heapq.heappop(heap)
弹出并返回 heap 的最小的元素,保持堆的不变性。如果堆为空,抛出 IndexError 。使用 heap[0] ,可以只访问最小的元素而不弹出它。
heapq.heappushpop(heap, item)
将 item 放入堆中,然后弹出并返回 heap 的最小元素。该组合操作比先调用 heappush() 再调用 heappop() 运行起来更有效率。
heapq.heapify(x)
将list x 转换成堆,原地,线性时间内。
heapq.heapreplace(heap, item)
弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变。 如果堆为空则引发 IndexError。
这个单步骤操作比 heappop() 加 heappush() 更高效,并且在使用固定大小的堆时更为适宜。 pop/push 组合总是会从堆中返回一个元素并将其替换为 item。
返回的值可能会比添加的 item 更大。 如果不希望如此,可考虑改用 heappushpop()。 它的 push/pop 组合会返回两个值中较小的一个,将较大的值留在堆中。
最大堆
class MaxHeap:
def __init__(self,x=[]):
self.data=[-i for i in x]
heapq.heapify(self.data)
def push(self,item):
heapq.heappush(self.data,-item)
def top(self):
return -self.data[0]
def pop(self):
return -heapq.heappop(self.data)
def pushpop(self,item):
return -heapq.heappushpop(self.data,-item)
def replace(self,item):
return -heapq.heapreplace(self.data,-item)
def __repr__(self):
return '['+",".join(map(lambda x:str(-x),self.data))+']'
q=[1,2,3,4,5]
q2=MaxHeap(q)
print(q2) #[5,4,3,1,2]
print(q2.pushpop(3.5)) #5
print(q2) #[4,3.5,3,1,2]
Java重写比较器
作者:Sparkk
链接:https://leetcode-cn.com/problems/minimum-operations-to-halve-array-sum/solution/by-sparkk-ipqq/
class Solution {
public int halveArray(int[] nums) {
long sum = 0;
double res = 0;
double target = 0;
int count = 0;
PriorityQueue<Double> que = new PriorityQueue<>((o1,o2) -> Double.compare(o2, o1));
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
que.add(nums[i] * 1.0);
}
target = sum * 1.0 / 2;
// 比较已减少的数量 与 和的一半
while (res < target) {
double temp = que.poll();
res += temp / 2;
que.add(temp / 2);
count++;
}
return count;
}
}
应用:
找第k大元素
多次取数组中最小元素,2208.将数组和减半的最少操作次数
链表
技巧:1.合并链表:添加哑节点
2.找链表的倒数第K个元素:用双指针
改变比较方式(优先队列中遇到),防止报错
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
pass
def __lt__(self, other):
return self.val < other.val
ListNode.__lt__ = __lt__
并查集
323.无向图中连通分量的数目
class Solution:
def countComponents(self, n: int, edges: List[List[int]]) -> int:
def find(x):
if fa[x]!=x:
fa[x]=find(fa[x])
return fa[x]
def merge(i,j):
x=find(i)
y=find(j)
if x!=y:
if rank[x]<=rank[y]:
fa[x]=y
else:
fa[y]=x
if rank[x]==rank[y]:
rank[y]+=1
self.count-=1
def ask(x,y):
return find(x)==find(y)
self.count=n
rank=[0]*n
fa=list(range(n))
for a,b in edges:
merge(a,b)
return self.count
树状数组
307区域和检索 - 数组可修改
'''BIT:Binary Indexed Tree 树状数组'''
class BIT:
def __init__(self, n):
self.tree = [0] * (n+1) # 比原数组多1个元素
def lowbit(self, x):
return x & (-x)
def add(self, i, delta): # 单点更新:执行+delta
i += 1 # 原数组下标转换到树状数组下标
while i<len(self.tree):
self.tree[i] += delta
i += self.lowbit(i)
def preSum(self, i): # 前缀和
i += 1 # 原数组下标转换到树状数组下标
summ = 0
while i>0:
summ += self.tree[i]
i -= self.lowbit(i)
return summ
def rangeSum(self, a, b): # 区间[a,b]的原数组和
return self.preSum(b) - self.preSum(a-1)
class NumArray:
def __init__(self, nums: List[int]):
self.nums=nums
self.tree = BIT(len(nums))
for i,v in enumerate(nums):
self.tree.add(i,v)
def update(self, index: int, val: int) -> None:
self.tree.add(index,val-self.nums[index])
self.nums[index]=val
def sumRange(self, left: int, right: int) -> int:
return self.tree.rangeSum(left,right)
# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# obj.update(index,val)
# param_2 = obj.sumRange(left,right)
线段树
题目链接:307. 区域和检索 - 数组可修改 - 力扣(LeetCode)
https://leetcode.cn/problems/range-sum-query-mutable/
参考教程:线段树从入门到急停 - 力扣(LeetCode)
https://leetcode.cn/circle/discuss/H4aMOn/
基本线段树1 (无懒标记,无区间修改方法,实时维护 nums[i])
支持:单点修改 / 单点查询 / 区间查询
class SegmentTree:
def __init__(self, nums):
self.nums=nums
self.n=len(self.nums)
self.tree = [0] * (4*self.n)
self.build(0,self.n-1,1)
def pushUp(self,i): #更新tree[i]
self.tree[i]=self.tree[i*2]+self.tree[i*2+1]
def build(self,s,t,i): #构建线段树(tree数组)
if s==t:
self.tree[i]=self.nums[s]
return
c=(s+t)//2
self.build(s,c,i*2)
self.build(c+1,t,i*2+1)
self.pushUp(i)
def update(self,i,x): #单点修改,驱动,nums[i]=x
self.add(i,x-self.nums[i],0,self.n-1,1)
self.nums[i]=x
def add(self,idx,x,s,t,i): #单点修改,nums[idx]+=x
if s==t:
self.tree[i]+=x
return
c=(s+t)//2
if idx<=c:
self.add(idx,x,s,c,i*2)
else:
self.add(idx,x,c+1,t,i*2+1)
self.pushUp(i)
def query(self,i): #单点查询,查询nums[i]
return self.nums[i]
def querySum(self,l,r): #区间查询,驱动,查询nums[l...r]
return self.sum(l,r,0,self.n-1,1)
def sum(self,l,r,s,t,i): #区间查询,查询nums[l...r]
if l<=s and t<=r:
return self.tree[i]
c=(s+t)//2
summ=0
if l<=c:
summ+=self.sum(l,r,s,c,i*2)
if r>c:
summ+=self.sum(l,r,c+1,t,i*2+1)
return summ
class NumArray:
def __init__(self, nums: List[int]):
self.seg=SegmentTree(nums)
def update(self, index: int, val: int) -> None:
self.seg.update(index,val)
def sumRange(self, left: int, right: int) -> int:
return self.seg.querySum(left,right)
二叉树-前序遍历
递归
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/er-cha-shu-de-qian-xu-bian-li-by-leetcode-solution/
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
def preorder(root: TreeNode):
if not root:
return
res.append(root.val)
preorder(root.left)
preorder(root.right)
res = list()
preorder(root)
return res
迭代
参考LeetCode-Solution
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans=[]
if not root:return ans #这行不必须
stack=[]
node=root
while stack or node:
while node:
ans.append(node.val)
stack.append(node)
node=node.left
node=stack.pop()
node=node.right
return ans
二叉树-中序遍历
递归
import sys
sys.setrecursionlimit(100000)
class Solution:
def inorderTraversal(self , root: TreeNode) -> List[int]:
ans=[]
def preOrder(x):
if not x:return
preOrder(x.left)
ans.append(x.val)
preOrder(x.right)
preOrder(root)
return ans
迭代
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans=[]
stack=[]
node=root
while stack or node:
while node:
stack.append(node)
node=node.left
node=stack.pop()
ans.append(node.val)
node=node.right
return ans
颜色标记法
颜色标记法-一种通用且简明的树遍历方法
henry
核心思想如下:
1使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
2如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
3如果遇到的节点为灰色,则将节点的值输出。
作者:hzhu212
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/
zjl233评论
本题需要中序遍历。
栈是一种 先进后出的结构,出栈顺序为左,中,右
那么入栈顺序必须调整为倒序,也就是右,中,左
同理,如果是前序遍历,入栈顺序为 右,左,中;后序遍历,入栈顺序中,右,左。
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
WHITE, GRAY = 0, 1
res = []
stack = [(WHITE, root)]
while stack:
color, node = stack.pop()
if node is None: continue
if color == WHITE:
stack.append((WHITE, node.right))
stack.append((GRAY, node))
stack.append((WHITE, node.left))
else:
res.append(node.val)
return res
二叉树-后序遍历
递归
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
def postorder(x):
if not x:
return
postorder(x.left)
postorder(x.right)
ans.append(x.val)
ans=[]
postorder(root)
return ans
迭代
参考LeetCode-Solution
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans=[]
if not root:
return ans
stack=[]
prev=None
node=root
while node or stack:
while node:
stack.append(node)
node=node.left
node=stack.pop()
if not node.right or node.right==prev:
ans.append(node.val)
prev=node
node=None
else:
stack.append(node)
node=node.right
return ans
前序的翻转
作者:carlsun-2
链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/bang-ni-dui-er-cha-shu-bu-zai-mi-mang-che-di-chi-t/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) return result;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
if (node->right) st.push(node->right); // 空节点不入栈
}
reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
return result;
}
};
二叉树-层序遍历
Mine-下标增加
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:return []
ans=[]
i=0
q=[]
q.append(root)
lastn=curn=1
while i<len(q):
anscur=[]
while i<lastn:
node=q[i]
anscur.append(node.val)
if node.left:
q.append(node.left)
curn+=1
if node.right:
q.append(node.right)
curn+=1
i+=1
lastn=curn
ans.append(anscur)
return ans
官方-dfs,cpp
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/er-cha-shu-de-ceng-xu-bian-li-by-leetcode-solution/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector <vector <int>> ret;
if (!root) {
return ret;
}
queue <TreeNode*> q;
q.push(root);
while (!q.empty()) {
int currentLevelSize = q.size();
ret.push_back(vector <int> ());
for (int i = 1; i <= currentLevelSize; ++i) {
auto node = q.front(); q.pop();
ret.back().push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return ret;
}
};
第二快,Python,列表模拟队列
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [root]
ans=[]
while queue:
path = []
for _ in range(len(queue)):
node = queue.pop(0)
path.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
ans.append(path) #原为ans.append(path[:])
return ans
双端队列
by霍格沃茨优秀毕业生,评论来自文章“BFS 的使用场景总结:层序遍历、最短路径问题”
from collections import deque
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
res = []
d = deque()
d.append(root)
while d:
length = len(d)
level = []
for i in range(length):
node = d.popleft()
level.append(node.val)
if node.left:
d.append(node.left)
if node.right:
d.append(node.right)
res.append(level)
return res
二叉树-最大深度
mine
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
return max(self.maxDepth(root.left),self.maxDepth(root.right))+1
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
def maxd(r,d):
if not r:
ans[0]=max(ans[0],d)
return
maxd(r.left,d+1)
maxd(r.right,d+1)
ans=[0]
maxd(root,0)
return ans[0]
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
q=[root]
ans=0
while q:
path=[]
for _ in range(len(q)):
node=q.pop(0)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
ans+=1
return ans
other
典型的深度优先搜索和广度优先搜索
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
# def recur(root): # DFS
# if not root:
# return 0
# left = recur(root.left)
# right = recur(root.right)
# return max(left, right)+1
# return recur(root)
# BFS
if not root:
return 0
deque = collections.deque([root])
Len = 0
while deque:
for _ in range(len(deque)):
tmp = deque.popleft()
if tmp.left:
deque.append(tmp.left)
if tmp.right:
deque.append(tmp.right)
Len += 1
return Len
二叉树-对称
1
/ \
/ \
/ \
/ \
2 2
/ \ / \
3 4 4 3
/ \ / \ / \ / \
8 7 6 5 5 6 7 8
递归-mine
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def isSym2(a,b):
if not a:
if not b:
return True
else:
return False
else:
if not b:
return False
if a.val!=b.val:
return False
return isSym2(a.left,b.right) and isSym2(a.right,b.left)
if not root:
return True
return isSym2(root.left,root.right)
迭代-每次提取两个结点
递归程序改写成迭代程序的常用方法
「方法一」中我们用递归的方法实现了对称性的判断,那么如何用迭代的方法实现呢?首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/symmetric-tree/solution/dui-cheng-er-cha-shu-by-leetcode-solution/
class Solution: #从官方cpp翻译
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
def isSym2(a,b):
q=[]
q.append(a)
q.append(b)
while q:
u=q.pop(0)
v=q.pop(0)
if not u and not v:
continue
if (not u or not v) or u.val!=v.val:
return False
q.append(u.left)
q.append(v.right)
q.append(u.right)
q.append(v.left)
return True
return isSym2(root.left,root.right)
算法
最短路dijkstra
官方:=743.网络延迟时间
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/network-delay-time/solution/wang-luo-yan-chi-shi-jian-by-leetcode-so-6phc/
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
g = [[] for _ in range(n)]
for x, y, time in times:
g[x - 1].append((y - 1, time))
dist = [float('inf')] * n
dist[k - 1] = 0
q = [(0, k - 1)]
while q:
time, x = heapq.heappop(q)
if dist[x] < time:
continue
for y, time in g[x]:
if (d := dist[x] + time) < dist[y]:
dist[y] = d
heapq.heappush(q, (d, y))
ans = max(dist)
return ans if ans < float('inf') else -1
最小堆+visited+dijkstra算法
作者:QRhqcDD90G
链接:https://leetcode-cn.com/problems/network-delay-time/solution/cpython3java-1po-su-dijkstrasuan-fa-2zui-ks36/
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
#------------------------最小堆+visited+dijkstra算法 -------------------------#
INF = 10 ** 9
adjvex = defaultdict(list)
for x, y, cost in times:
x -= 1
y -= 1
adjvex[x].append((y, cost))
start = k - 1 #起点
dist = [INF for _ in range(n)]
visited = [False for _ in range(n)]
dist[start] = 0
minHeap = []
heapq.heappush(minHeap, (0, start))
while minHeap:
d, x = heapq.heappop(minHeap)
if visited[x] == True:
continue
visited[x] = True
for y, cost in adjvex[x]:
if dist[x] + cost < dist[y]:
dist[y] = dist[x] + cost
heapq.heappush(minHeap, (dist[y], y))
#----- 最后一个结点收到的时间。是求max
res = max(dist)
return res if res != INF else -1
三条最短路by灵茶山艾府
题目:2203.得到要求路径的最小带权子图
枚举三条最短路的交汇点_灵茶山艾府
作者:endlesscheng
链接:https://leetcode-cn.com/problems/minimum-weighted-subgraph-with-the-required-paths/solution/by-endlesscheng-2mxm/
class Solution:
def minimumWeight(self, n: int, edges: List[List[int]], src1: int, src2: int, dest: int) -> int:
def dijkstra(g: List[List[tuple]], start: int) -> List[int]:
dis = [inf] * n
dis[start] = 0
pq = [(0, start)]
while pq:
d, x = heappop(pq)
if d > dis[x]:
continue
for y, wt in g[x]:
new_d = dis[x] + wt
if new_d < dis[y]:
dis[y] = new_d
heappush(pq, (new_d, y))
return dis
g = [[] for _ in range(n)]
rg = [[] for _ in range(n)]
for x, y, wt in edges:
g[x].append((y, wt))
rg[y].append((x, wt))
d1 = dijkstra(g, src1)
d2 = dijkstra(g, src2)
d3 = dijkstra(rg, dest)
ans = min(sum(d) for d in zip(d1, d2, d3))
return ans if ans < inf else -1
拓扑排序
课程表 II - 课程表 II - 力扣(LeetCode) https://leetcode.cn/problems/course-schedule-ii/solution/ke-cheng-biao-ii-by-leetcode-solution/
210官方,BFS,用了collections
用了collections的defaultdict和deque
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
# 存储有向图
edges = collections.defaultdict(list)
# 存储每个节点的入度
indeg = [0] * numCourses
# 存储答案
result = list()
for info in prerequisites:
edges[info[1]].append(info[0])
indeg[info[0]] += 1
# 将所有入度为 0 的节点放入队列中
q = collections.deque([u for u in range(numCourses) if indeg[u] == 0])
while q:
# 从队首取出一个节点
u = q.popleft()
# 放入答案中
result.append(u)
for v in edges[u]:
indeg[v] -= 1
# 如果相邻节点 v 的入度为 0,就可以选 v 对应的课程了
if indeg[v] == 0:
q.append(v)
if len(result) != numCourses:
result = list()
return result
mine,BFS,没用collections
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
n=numCourses
deg=[0]*n #入度
nex=[[] for _ in range(n)] #之后的课程,nex[i]依赖i
for a,b in prerequisites: # b指向a
deg[a]+=1
nex[b].append(a)
q=[]
for i,v in enumerate(deg):
if v==0:
q.append(i)
ans=[]
while q:
u=q.pop(0)
ans.append(u)
for v in nex[u]:
deg[v]-=1
if deg[v]==0:
q.append(v)
if len(ans)==n:
return ans
return []
207官方,只判断是否有环
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
edges = collections.defaultdict(list)
indeg = [0] * numCourses
for info in prerequisites:
edges[info[1]].append(info[0])
indeg[info[0]] += 1
q = collections.deque([u for u in range(numCourses) if indeg[u] == 0])
visited = 0
while q:
visited += 1
u = q.popleft()
for v in edges[u]:
indeg[v] -= 1
if indeg[v] == 0:
q.append(v)
return visited == numCourses
6163.给定条件下构造矩阵by灵茶山艾府
作者:endlesscheng
链接:https://leetcode.cn/problems/build-a-matrix-with-conditions/solution/by-endlesscheng-gpev/
class Solution:
def buildMatrix(self, k: int, rowConditions: List[List[int]], colConditions: List[List[int]]) -> List[List[int]]:
def topo_sort(edges: List[List[int]]) -> List[int]:
g = [[] for _ in range(k)]
in_deg = [0] * k
for x, y in edges:
g[x - 1].append(y - 1) # 顶点编号从 0 开始,方便计算
in_deg[y - 1] += 1
order = []
q = deque(i for i, d in enumerate(in_deg) if d == 0)
while q:
x = q.popleft()
order.append(x)
for y in g[x]:
in_deg[y] -= 1
if in_deg[y] == 0:
q.append(y)
return order if len(order) == k else None
if (row := topo_sort(rowConditions)) is None or (col := topo_sort(colConditions)) is None:
return []
pos = {x: i for i, x in enumerate(col)}
ans = [[0] * k for _ in range(k)]
for i, x in enumerate(row):
ans[i][pos[x]] = x + 1
return ans
二分法
我的思路(纯属记录,可忽略看其他教程,如有错麻烦指出)
先看等于时,划入那一边
再看该边应该是大于还是小于
最后(循环外)处理边界(始终不发生某条件,可能下标要更改1)
看是否包含解,来设置mid加减1
m偏向哪一边的两个情形
m=(zo+yo)//2
yo=m
zo=m+1
m=(zo+yo+1)//2
yo=m-1
zo=m
一规律
二分查找通用规律(固定模板解决寻找>=, >, <, <=)
/**
* 范围查询规律
* 初始化:
* int left = 0;
* int right = nums.length - 1;
* 循环条件
* left <= right
* 右边取值
* right = mid - 1
* 左边取值
* left = mid + 1
* 查询条件
* >= target值, 则 nums[mid] >= target时, 都减right = mid - 1
* > target值, 则 nums[mid] > target时, 都减right = mid - 1
* <= target值, 则 nums[mid] <= target时, 都加left = mid + 1
* < target值, 则 nums[mid] < target时, 都加left = mid + 1
* 结果
* 求大于(含等于), 返回left
* 求小于(含等于), 返回right
* 核心思想: 要找某个值, 则查找时遇到该值时, 当前指针(例如right指针)要错过它, 让另外一个指针(left指针)跨过他(体现在left <= right中的=号), 则找到了
*/
作者:chendragon
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/er-fen-cha-zhao-tong-yong-gui-lu-gu-ding-g93u/
回溯
39组合总和
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
ans=[]
def dfs(pre,ind,ta):
print(pre,ind,ta)
if ind==len(candidates) or candidates[ind]>ta:
return
if candidates[ind]==ta:
ans.append(pre+[ta])
return
dfs(pre+[candidates[ind]],ind,ta-candidates[ind])
dfs(pre,ind+1,ta)
dfs([],0,target)
return ans
40组合总和2
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
n=len(candidates)
candidates.sort()
ans=[]
def dfs(pre,ind,ta,last):
if ind==n or candidates[ind]>ta:
return
if candidates[ind]==ta:
ans.append(pre+[ta])
return
if candidates[ind]!=last:
dfs(pre+[candidates[ind]],ind+1,ta-candidates[ind],-1)
dfs(pre,ind+1,ta,candidates[ind])
dfs([],0,target,-1)
return ans
其他
技巧
1.通常先排序,如2126. 摧毁小行星,除了少数对元素顺序有要求的(如2210. 统计数组中峰和谷的数量)
2.有时先去重会少很多麻烦,如上文提到的2210题;集合去重
易错
- 2+1&2结果是2,因为&的优先级低于+,2|3&1结果是3
出现题目:2172数组的最大与和 - 力扣(LeetCode)
https://leetcode-cn.com/problems/maximum-and-sum-of-array/
-
数组中出现负数,与非负处理有所不同
-
Python中nums[-k]不会报错,但是k为0时导致结果不对
dp[k][i]=max((dp[k][i-1] if i>=1 else 0),
(dp[k-1][i-le] if i-le>=0 else 0)+pre[i]-(pre[i-le] if i-le>=0 else 0))
- 当数组的第零个元素被忽略时,数组长度n加一,所有的地方n都要改为n+1。
inf=float('inf')
edges=[[inf]*(n+1) for i in range(n+1)]
while True:
for i in range(n+1):
- Python的q.pop(0)少了0
日期,一年的第多少天
year=int(input("请输入年份:"))
month=int(input("请输入月份:"))
day=int(input("请输入日期:"))
sum=0
months=(31,28,31,30,31,30,31,31,30,31,30,31)
for i in range(month-1):
sum+=months[i]
sum+=day
leap=0
if (year%400==0) or (year%4==0 and year%100!=0):
leap=1
if leap==1 and month>2:
sum+=1
print("It is the {} day".format(sum))
经典题目
300.最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
官方,贪心 + 二分查找
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-by-leetcode-soluti/
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
d = []
for n in nums:
if not d or n > d[-1]:
d.append(n)
else:
l, r = 0, len(d) - 1
loc = r
while l <= r:
mid = (l + r) // 2
if d[mid] >= n:
loc = mid
r = mid - 1
else:
l = mid + 1
d[loc] = n
return len(d)
含有等于情形,动态规划 + 二分查找
作者:jyd
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-dong-tai-gui-hua-2/
# Dynamic programming + Dichotomy.
class Solution:
def lengthOfLIS(self, nums: [int]) -> int:
tails, res = [0] * len(nums), 0
for num in nums:
i, j = 0, res
while i < j:
m = (i + j) // 2
if tails[m] < num: i = m + 1
# 如果要求非严格递增,将此行 '<' 改为 '<=' 即可。
else: j = m
tails[i] = num
if j == res: res += 1
return res
最长公共子串
0.dp_mine
class Solution:
def findLength(self, nums1: List[int], nums2: List[int]) -> int:
n=len(nums1)
m=len(nums2)
maxl=0
dp=[[0]*(m+1) for i in range(n+1)]
for i in range(1,n+1):
for j in range(1,m+1):
if nums1[i-1]==nums2[j-1]:
dp[i][j]=1+dp[i-1][j-1]
else:
dp[i][j]=0
if dp[i][j]>maxl:
# i1,j1=i,j
maxl=dp[i][j]
# print(nums1[i1-maxl:i1])
return maxl
1.dp官方
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/zui-chang-zhong-fu-zi-shu-zu-by-leetcode-solution/
class Solution:
def findLength(self, A: List[int], B: List[int]) -> int:
n, m = len(A), len(B)
dp = [[0] * (m + 1) for _ in range(n + 1)]
ans = 0
for i in range(n - 1, -1, -1):
for j in range(m - 1, -1, -1):
dp[i][j] = dp[i + 1][j + 1] + 1 if A[i] == B[j] else 0
ans = max(ans, dp[i][j])
return ans
2.哈希+二分
class Solution:
#https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/zui-chang-zhong-fu-zi-shu-zu-by-leetcode-solution/
def findLength(self, A: List[int], B: List[int]) -> int:
base, mod = 113, 10**9 + 9
def check(length: int) -> bool:
hashA = 0
for i in range(length):
hashA = (hashA * base + A[i]) % mod
bucketA = {hashA}
mult = pow(base, length - 1, mod)
for i in range(length, len(A)):
hashA = ((hashA - A[i - length] * mult) * base + A[i]) % mod
bucketA.add(hashA)
hashB = 0
for i in range(length):
hashB = (hashB * base + B[i]) % mod
if hashB in bucketA:
return True
for i in range(length, len(B)):
hashB = ((hashB - B[i - length] * mult) * base + B[i]) % mod
if hashB in bucketA:
return True
return False
left, right = 0, min(len(A), len(B))
ans = 0
while left <= right:
mid = (left + right) // 2
if check(mid):
ans = mid
left = mid + 1
else:
right = mid - 1
return ans
最长公共子序列
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-subsequence/solution/zui-chang-gong-gong-zi-xu-lie-by-leetcod-y7u0/
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m, n = len(text1), len(text2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i - 1] == text2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
不同的子序列
作者:powcai
链接:https://leetcode-cn.com/problems/distinct-subsequences/solution/dong-tai-gui-hua-by-powcai-5/
class Solution:
def numDistinct(self, s: str, t: str) -> int:
n1=len(s)
n2=len(t)
dp=[[0]*(n1+1) for _ in range(n2+1)]
for j in range(n1+1):
dp[0][j]=1
for i in range(1,n2+1):
for j in range(1,n1+1):
if t[i-1]==s[j-1]:
dp[i][j]=dp[i-1][j-1]+dp[i][j-1]
else:
dp[i][j]=dp[i][j-1]
return dp[-1][-1]
数组中的逆序对,剑指 Offer 51
方法一:归并排序
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/shu-zu-zhong-de-ni-xu-dui-by-leetcode-solution/
class Solution:
def mergeSort(self, nums, tmp, l, r):
if l >= r:
return 0
mid = (l + r) // 2
inv_count = self.mergeSort(nums, tmp, l, mid) + self.mergeSort(nums, tmp, mid + 1, r)
i, j, pos = l, mid + 1, l
while i <= mid and j <= r:
if nums[i] <= nums[j]:
tmp[pos] = nums[i]
i += 1
inv_count += (j - (mid + 1))
else:
tmp[pos] = nums[j]
j += 1
pos += 1
for k in range(i, mid + 1):
tmp[pos] = nums[k]
inv_count += (j - (mid + 1))
pos += 1
for k in range(j, r + 1):
tmp[pos] = nums[k]
pos += 1
nums[l:r+1] = tmp[l:r+1]
return inv_count
def reversePairs(self, nums: List[int]) -> int:
n = len(nums)
tmp = [0] * n
return self.mergeSort(nums, tmp, 0, n - 1)
方法二:离散化树状数组
class BIT:
def __init__(self, n):
self.n = n
self.tree = [0] * (n + 1)
@staticmethod
def lowbit(x):
return x & (-x)
def query(self, x):
ret = 0
while x > 0:
ret += self.tree[x]
x -= BIT.lowbit(x)
return ret
def update(self, x):
while x <= self.n:
self.tree[x] += 1
x += BIT.lowbit(x)
class Solution:
def reversePairs(self, nums: List[int]) -> int:
n = len(nums)
# 离散化
tmp = sorted(nums)
for i in range(n):
nums[i] = bisect.bisect_left(tmp, nums[i]) + 1
# 树状数组统计逆序对
bit = BIT(n)
ans = 0
for i in range(n - 1, -1, -1):
ans += bit.query(nums[i] - 1)
bit.update(nums[i])
return ans
Python有序集合 + 二分查找实现
by我爱志方小姐
发布于 2022-09-19
求逆序对问题:
上面三个求 逆序对问题 都可以用下面两种方法做,代码也几乎一毛一样~ 😂
作者:shikata-akiko-fans
链接:https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/by-shikata-akiko-fans-e1oq/
方法一:有序集合 + 二分查找
from sortedcontainers import SortedList
class Solution:
def reversePairs(self, nums: List[int]) -> int:
n = len(nums)
res = 0
sl = SortedList()
for i in range(n - 1, -1, -1):
res += sl.bisect_left(nums[i])
sl.add(nums[i])
return res
方法二:手动维护普通列表有序 + 二分查找
class Solution:
def reversePairs(self, nums: List[int]) -> int:
n = len(nums)
res = 0
sl = []
for i in range(n - 1, -1, -1):
idx = bisect.bisect_left(sl, nums[i])
res += idx
sl.insert(idx, nums[i])
return res
2426满足不等式的数对数目
离散化,二分,树状数组
作者:endlesscheng
链接:https://leetcode.cn/problems/number-of-pairs-satisfying-inequality/solution/by-endlesscheng-9prc/
class Solution:
def numberOfPairs(self, a: List[int], nums2: List[int], diff: int) -> int:
for i, x in enumerate(nums2):
a[i] -= x
b = a.copy()
b.sort() # 配合下面的二分,离散化
ans = 0
t = BIT(len(a) + 1)
for x in a:
ans += t.query(bisect_right(b, x + diff))
t.add(bisect_left(b, x) + 1)
return ans
class BIT:
def __init__(self, n):
self.tree = [0] * n
def add(self, x):
while x < len(self.tree):
self.tree[x] += 1
x += x & -x
def query(self, x):
res = 0
while x > 0:
res += self.tree[x]
x &= x - 1
return res
加一个偏移量,树状数组
作者:tsreaper
链接:https://leetcode.cn/problems/number-of-pairs-satisfying-inequality/solution/by-tsreaper-dsyn/
class Solution {
const int MAXA = 1e4;
// 把所有数都加一个偏移量变成正数
const int BASE = MAXA * 3 + 1;
vector<int> tree;
int lb(int x) { return x & (-x); }
void add(int pos, int val) {
pos += BASE;
for (; pos < tree.size(); pos += lb(pos)) tree[pos] += val;
}
int query(int pos) {
pos += BASE;
int ret = 0;
for (; pos; pos -= lb(pos)) ret += tree[pos];
return ret;
}
public:
long long numberOfPairs(vector<int>& nums1, vector<int>& nums2, int diff) {
int n = nums1.size();
// 注意 nums1[j] - nums2[j] + diff 的值最小可到 -3 * MAXA,最大可到 3 * MAXA,
// 因此要开 6 * MAXA + 1 的空间
tree.resize(MAXA * 6 + 10);
long long ans = 0;
for (int i = 0; i < n; i++) {
ans += query(nums1[i] - nums2[i] + diff);
add(nums1[i] - nums2[i], 1);
}
return ans;
}
};
SortedList
作者:FreeYourMind
链接:https://leetcode.cn/problems/number-of-pairs-satisfying-inequality/solution/by-freeyourmind-92uc/
from sortedcontainers import SortedList
class Solution:
def numberOfPairs(self, nums1: List[int], nums2: List[int], diff: int) -> int:
res, sl = 0, SortedList()
for x in (a - b for a, b in zip(nums1, nums2)):
res += sl.bisect_right(x + diff)
sl.add(x)
return res
树状数组+偏移
class Solution:
def numberOfPairs(self, nums1: List[int], nums2: List[int], diff: int) -> int:
res, bit = 0, BIT(50005)
for x in (a - b + 20002 for a, b in zip(nums1, nums2)):
res += bit.sum(x + diff + 1)
bit[x] += 1
return res
239.滑动窗口最大值
mine堆
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
ans=[]
a=[(-v,i) for i,v in enumerate(nums[:k-1])]
heapq.heapify(a)
for i,v in enumerate(nums[k-1:],k-1):
heapq.heappush(a,(-v,i))
vm,im=a[0]
while im+k<=i:
heapq.heappop(a)
vm,im=a[0]
ans.append(-vm)
return ans
st表=稀疏表
ST 表 - OI Wiki https://oi-wiki.org/ds/sparse-table/
ST 表是用于解决 可重复贡献问题 的数据结构。可重复贡献问题 是指对于运算opt ,满足x opt x=x ,则对应的区间询问就是一个可重复贡献问题。
RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。
ST表 python实现_在北京挖石油的日子的博客-CSDN博客_python st表 https://blog.csdn.net/m0_60961645/article/details/123684122
import math
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n=len(nums)
f = [[0]*21 for i in range(1+n)]
for i in range(n):
f[i][0] = nums[i]
for j in range(1,int(math.log2(n))+1):
for i in range(n-2**j+1):
f[i][j] = max(f[i][j-1],f[i+2**(j-1)][j-1])
ans=[]
for i in range(n-k+1):
l,r = i,i+k-1
s = int(math.log2(r-l+1))
ans.append(max(f[l][s],f[r-2**s+1][s]))
return ans
官方堆
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/sliding-window-maximum/solution/hua-dong-chuang-kou-zui-da-zhi-by-leetco-ki6m/
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
# 注意 Python 默认的优先队列是小根堆
q = [(-nums[i], i) for i in range(k)]
heapq.heapify(q)
ans = [-q[0][0]]
for i in range(k, n):
heapq.heappush(q, (-nums[i], i))
while q[0][1] <= i - k:
heapq.heappop(q)
ans.append(-q[0][0])
return ans
单调队列
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
q = collections.deque()
for i in range(k):
while q and nums[i] >= nums[q[-1]]:
q.pop()
q.append(i)
ans = [nums[q[0]]]
for i in range(k, n):
while q and nums[i] >= nums[q[-1]]:
q.pop()
q.append(i)
while q[0] <= i - k:
q.popleft()
ans.append(nums[q[0]])
return ans
分块 + 预处理
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
prefixMax, suffixMax = [0] * n, [0] * n
for i in range(n):
if i % k == 0:
prefixMax[i] = nums[i]
else:
prefixMax[i] = max(prefixMax[i - 1], nums[i])
for i in range(n - 1, -1, -1):
if i == n - 1 or (i + 1) % k == 0:
suffixMax[i] = nums[i]
else:
suffixMax[i] = max(suffixMax[i + 1], nums[i])
ans = [max(suffixMax[i], prefixMax[i + k - 1]) for i in range(n - k + 1)]
return ans
56.合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
https://leetcode-cn.com/problems/merge-intervals/solution/he-bing-qu-jian-by-leetcode-solution/
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort(key=lambda x: x[0])
merged = []
for interval in intervals:
# 如果列表为空,或者当前区间与上一区间不重合,直接添加
if not merged or merged[-1][1] < interval[0]:
merged.append(interval)
else:
# 否则的话,我们就可以与上一区间进行合并
merged[-1][1] = max(merged[-1][1], interval[1])
return merged
986.区间列表的交集
给定两个由一些 闭区间 组成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序 。
返回这 两个区间列表的交集 。
形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b 。
两个闭区间的 交集 是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3] 。
示例 1:
输入:firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
作者:LeetCode
链接:https://leetcode-cn.com/problems/interval-list-intersections/solution/qu-jian-lie-biao-de-jiao-ji-by-leetcode/
class Solution:
def intervalIntersection(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
ans = []
i = j = 0
while i < len(A) and j < len(B):
# Let's check if A[i] intersects B[j].
# lo - the startpoint of the intersection
# hi - the endpoint of the intersection
lo = max(A[i][0], B[j][0])
hi = min(A[i][1], B[j][1])
if lo <= hi:
ans.append([lo, hi])
# Remove the interval with the smallest endpoint
if A[i][1] < B[j][1]:
i += 1
else:
j += 1
return ans
191.位1的个数
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/number-of-1-bits/solution/wei-1de-ge-shu-by-leetcode-solution-jnwf/
循环检查二进制位 if n & (1 << i))
class Solution:
def hammingWeight(self, n: int) -> int:
ret = sum(1 for i in range(32) if n & (1 << i))
return ret
Brian Kernighan 算法
class Solution:
def hammingWeight(self, n: int) -> int:
ret = 0
while n:
n &= n - 1
ret += 1
return ret
具体地,该算法可以被描述为这样一个结论:记 f(x)表示 x 和 x-1 进行与运算所得的结果(即 f(x)=x & (x-1)),那么 f(x) 恰为 x 删去其二进制表示中最右侧的 1 的结果。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode-solution-u1w7/
循环检查二进制位 tmp >>= 1
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/minimum-bit-flips-to-convert-number/solution/zhuan-huan-shu-zi-de-zui-shao-wei-fan-zh-awf2/
class Solution:
def minBitFlips(self, start: int, goal: int) -> int:
res = 0
tmp = start ^ goal
while tmp:
res += tmp & 1
tmp >>= 1
return res
Python一行
return bin(n).count("1")
Integer.bitCount() 函数理解(尽量通俗易懂)喜欢下雨所以爱上雷震子的博客-CSDN博客_integer.bitcount https://blog.csdn.net/qq_27007509/article/details/112246576
Jdk1.8
public static int bitCount(int i) {
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}