Python算法题笔记

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
求逆序对问题:

315. 计算右侧小于当前元素的个数

493. 翻转对

剑指 Offer 51. 数组中的逆序对

上面三个求 逆序对问题 都可以用下面两种方法做,代码也几乎一毛一样~ 😂

作者: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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值