本文不定期更新
1 新的提交方式
在第一次接触力扣代码模版的时候可能会有点懵,毕竟跟传统OJ有些许不同,它不需要你写出main函数,只要完成它提供的一个类即可,以2236. 判断根结点是否等于子结点之和为例。
其中模版里给出的checkTree
类方法是你要输出答案的方法,你只需在该方法中完成算法,并返回正确答案即可。
函数参数root:Optional[TreeNode]
,表示函数参数root
是个自定义类:TreeNode
。
“-> bool
”表示函数返回值是布尔类型。
上述变量类型的提示不是写给编译器看的,而是给IDE和编程人员看的。当然,你完全可以写成“def checkTree(self,head):
”,但是这样代码的可读性就大大降低了。养成良好的编程习惯,也是每个OIer的必修课。
图中有一个被注释的类TreeNode
,它是提示你判题器里自带这个类,但你在本地调试的时候需要自己加上这个类,就像这样:(解除它的注释即可)
2 如何快速判断你的算法是否会TLE
一般我们可以认为编译器每秒可运行1亿条语句,以18. 四数之和为例,提示中告诉你数组nums的最大长度为200,我们可以计算遍历nums数组使用 O ( n 3 ) O(n^3) O(n3)复杂度的算法最多运行语句量为: 20 0 3 = 8 ∗ 1 0 6 < 1 0 8 200^{3}=8*10^{6}<10^{8} 2003=8∗106<108,因此这题可以放心大胆地用双重for循环加双指针啦~。
其它注意点
使用in
语句时有时需要考虑它的时间复杂度
list = [i for i in range(10000)]
if 1001 in list:
return ture
else
return false
以上代码段是使用in
语句判断是否存在某数,对list
类型的变量使用in
操作符,它的时间复杂度是
O
(
n
)
O(n)
O(n),这点需要注意。但字典的查询操作是
O
(
1
)
O(1)
O(1),因为它使用的是哈希函数。
3 语法部分
3.1 面向对象语法
3.1.1slots
限制属性
__slots__
用于限制该实例的属性,下面这段语句就限制了SegmentTree
这个类只能有root
这个属性
class SegmentTree():
__slots__ = ["root"]
def __init__(self, right: int = int(1e9)):
self.root = Node()
self.root.range = [1, right]
3.1.2 类初始化设置默认值
这个比较简单,接上部分代码,在right: int = int(1e9)
中我就声明了right
的变量类型为int
且初始值为
1
0
9
10^{9}
109,你也可以right = int(1e9)
来声明默认值
3.2 迭代对象语法
3.2.1 map
函数
map函数可以对一个迭代对象的所有元素进行统一操作,并返回一个map类型的值,给出以下代码体会一下:
对单个迭代对象的操作
# 对a中所有元素求平方
if __name__ == '__main__':
a = [1,2,3]
b = list(map(lambda x: x**2, a))
print(b)
# 输出[1, 4, 9]
还可以对字符串操作
# 求数位和
if __name__ == '__main__':
num = "1234"
s=sum(map(int, num))
print(s)
# 输出10
# map(int, num)=map([1,2,3,4])
当然你可以使用自定义的函数
# 对a中所有元素求平方
def square(x:int) -> int:
return x**2
if __name__ == '__main__':
a = [1,2,3]
b = list(map(square, a))
print(b)
# 输出[1, 4, 9]
# 将a中所有元素转为字符串
if __name__ == '__main__':
a = [1,2,3]
b = list(map(str, a))
print(b)
# 输出['1', '2', '3']
对多个迭代对象的操作
# 按元素下标合并 a,b 两个列表
if __name__ == '__main__':
a = [1,2,3]
b = [1,2,3]
c = list(map(lambda x, y: x+y, a, b))
print(c)
# 输出[2, 4, 6]
3.2.2 join
函数
join函数主要用于字符串列表、字符串等变量,用于在拼接字符串时插入分隔符,返回类型是字符串。
if __name__ == '__main__':
a = ['1', '2', '3']
print(f"对字符串列表{a}使用\',\'.join: {','.join(a)}")
b = "123"
print(f"对字符串{b}使用\',\'.join: {','.join(b)}")
'''
输出:
对字符串列表['1', '2', '3']使用','.join: 1,2,3
对字符串123使用','.join: 1,2,3
'''
3.2.3 列表初始化
有两种初始化方法,上代码体会:
a = [0]*10
print(a)
# 输出[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
a = [[0]*10]*2
print(a)
# 输出[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
a = [i for i in range(10)]
print(a)
# 输出[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a = [[i] for i in range(10)]
print(a)
# 输出[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]
3.2.4 主次排序
利用lambda
语法设置主次元素
arr = [(1,4,3),(1,3,3),(2,1,4),(3,5,1)]
arr = sorted(arr, key= lambda s:(s[0],s[1])) #两个关键字的主次排序
3.2.5 按照元素值对元素下标排序
需求如题,代码如下。来自LeetCode 1851. 包含每个查询的最小区间
if __name__ == '__main__':
queries = [5,3,4,2]
qindex = list(range(len(queries))) # 生成列表[0,1,2,...,n-1],其中 n = len(queries)
qindex.sort(key=lambda i: queries[i]) # 按照queries[i]的对应值对qindex排序,其实就是保持queries数组不变,对它的下标进行排序
print(qindex)
# 输出结果是[3, 1, 2, 0],自己可以改变queries 的值尝试一下
3.2.6 counter
统计函数
Counter() 是 collections 库中的一个函数,可以用来统计一个 python 列表、字符串、元组等可迭代对象中每个元素出现的次数,并返回一个Counter类型的变量,它继承至dict
(字典)。
以2085. 统计出现过一次的公共字符串为例,题目是:给你两个字符串数组 words1
和 words2
,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。
这时我们就可以用Counter函数来统计词频了
class Solution:
def countWords(self, words1: List[str], words2: List[str]) -> int:
count1 = Counter(words1)
count2 = Counter(words2)
ans = 0
for k, v in count1.items():
if v == count2.get(k,0) and v == 1:
ans += 1
return ans
"""
在这段代码中
count1=Counter({'is': 2, 'leetcode': 1, 'amazing': 1, 'as': 1})
count1=Counter({'amazing': 1, 'leetcode': 1, 'is': 1})
"""
if __name__ == '__main__':
solution = Solution()
words1 = ["leetcode", "is", "amazing", "as", "is"]
words2 = ["amazing", "leetcode", "is"]
print(solution.countWords(words1,words2))
3.2.7 列表反转
需求:我们有列表list
对象a=[1,2,3,4]
需要得到b=[4,3,2,1]
方法1:可以使用list[::-1]
,字符串对象也可以使用这个方法
b=a[::-1]
a
变量不影响,b
申请的额外空间
方法2:使用方法list.reverse()
b=a.reverse()
reverse
方法是直接在a
变量空间上执行逆序操作,因此b
引用了a
的地址空间。
该方法其实会直接在原来的列表里面将元素进行逆序排列,不需要创建新的副本用于存储结果,不需要重新申请空间来保存最后的结果,但是修改了原来的数据。
拓展:reversed()
函数,它会将列表逆序的结果存储到迭代器里面,这种方式不会改变原来的列表,也不会创建原来列表的完整副本,只会多出迭代器对象所占的空间,相对来说也比较高效。也就是说其返回值是一个迭代器,你可以将其理解为一个指针,指向原来的列表。
b = []
for i in reversed(a):
b.append(i)
3.2.8 二分查找bisect
库
bisect
库有三个函数:bisect
、bisect_right
、bisect_left
,用法如下:
import bisect
ls = [1,5,9,13,17]
index1 = bisect.bisect(ls,9)
index2 = bisect.bisect_left(ls,9)
index3 = bisect.bisect_right(ls,9)
print(f"index1 = {index1}, index2 = {index2}, index3 = {index3}")
###
输出
index1 = 3, index2 = 2, index3 = 3
###
其中bisect
、bisect_right
等同,都是找列表中第一个大于该元素的下标,而bisect_left
返回列表中第一个大于等于该元素的下标。
3.2.9 set
创建集合
语法:
class set(iterable)
如果想将一个list
转换为哈希表用于查询可以使用set
方法,具体用法如下:
x = set('python')
# x = set(['p','y','t','h','o','n'])
y = set([0,1,2,3])
# y = set([0,1,2,3])
y.add(4)
# y = set([0,1,2,3,4])
# 在创建集合时能自动过滤重复元素,创建不重复的集合
交、并、差集合运算:
>>> x = set('runoob')
>>> y = set('google')
>>> x, y
(set(['b', 'r', 'u', 'o', 'n']), set(['e', 'o', 'g', 'l'])) # 重复的被删除
>>> x & y # 交集
set(['o'])
>>> x | y # 并集
set(['b', 'e', 'g', 'l', 'o', 'n', 'r', 'u'])
>>> x - y # 差集
set(['r', 'b', 'u', 'n'])
>>>
对集合元素访问的时间复杂度是常数,因此可以当作哈希表
3.3 字典对象函数&方法
函数 | 描述 | 实例 |
---|---|---|
len(dict) | 计算字典元素个数,即键的总数。 | >>> tinydict = {‘Name’: ‘Runoob’, ‘Age’: 7, ‘Class’: ‘First’} >>> len(tinydict) >>> 3 |
str(dict) | 输出字典,可以打印的字符串表示。 | >>> tinydict = {‘Name’: ‘Runoob’, ‘Age’: 7, ‘Class’: ‘First’} >>> str(tinydict) >>> “{‘Name’: ‘Runoob’, ‘Class’: ‘First’, ‘Age’: 7}” |
type(variable) | 返回输入的变量类型,如果变量是字典就返回字典类型。 | >>> tinydict = {‘Name’: ‘Runoob’, ‘Age’: 7, ‘Class’: ‘First’} >>> type(tinydict) >>> <class ‘dict’> |
方法 | 描述 |
---|---|
dict.clear() | 删除字典内所有元素 |
dict.copy() | 返回一个字典的浅复制 |
dict.fromkeys() | 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
dict.get(key, default=None) | 返回指定键的值,如果键不在字典中返回 default 设置的默认值 |
key in dict | 如果键在字典dict里返回true,否则返回false |
dict.items() | 以列表返回一个视图对象 |
dict.keys() | 返回一个视图对象 |
dict.setdefault(key, default=None) | 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
dict.update(dict2) | 把字典dict2的键/值对更新到dict里 |
dict.values() | 返回一个视图对象 |
pop(key\[,default\]) | 删除字典 key(键)所对应的值,返回被删除的值。 |
popitem() | 返回并删除字典中的最后一对键和值。 |
3.3.1 活用get
方法
如果有这么一个需求:我们需要统计字典中所有元素的出现次数
那么在给元素统计次数的时候,我们需要判断该元素是否字典中出现,如果出现则在原值上+1
,如果没有则需要赋一个初值,我们很容易想到一个简单的写法:
if key in dict:
dict[key]+=1
else:
dict[key]=1
但如果我们活用get(key,default)
方法,代码就能简洁很多了。
dict[key]=dict.get(key,1)+1
4 数学知识
4.1 异或等式
a ⊕ b = c ⟹ a ⊕ c = b ⟹ c ⊕ b = a a \oplus b = c \Longrightarrow a \oplus c = b \Longrightarrow c \oplus b = a a⊕b=c⟹a⊕c=b⟹c⊕b=a
4.2 小数求余不精确问题
小数求余不准的问题:
2681. 英雄的力量这题如果提交以下代码会报错,但如果将MOD
转为int
就对了。
class Solution:
def sumOfPower(self, nums: List[int]) -> int:
MOD = 1e9+7
nums = sorted(nums)
ans, s = 0, 0
for i in range(len(nums)):
ans = (nums[i]**2*(nums[i]+s) + ans) % MOD
s = (nums[i] + s*2) % MOD
return int(ans)
4.3 同余定理
i f a % b = c , t h e n ( a + k × b ) % b = c ; ( k ∈ Z a n d k ≠ 0 ) i f a % b = c , t h e n ( k × a ) % b = k × c % b ; ( k ∈ N ∗ ) 满足类似于分配律的等式 ( a + b ) % c = ( ( a % c ) + ( b % c ) ) % c ; ( a × b ) % c = ( ( a % c ) × ( b % c ) ) % c ; \begin{matrix} if\ a\%b = c,\ then\ (a+k\times b)\%b = c; (k\in Z\ and\ k\ne 0)\\ if\ a\%b = c,\ then\ (k\times a)\%b = k\times c\%b; (k\in N^{*})\\ 满足类似于分配律的等式\\ (a + b) \% c = ((a \% c) + (b \% c)) \% c;\\ (a \times b) \% c = ((a \% c) \times (b \% c)) \% c;\\ \end{matrix} if a%b=c, then (a+k×b)%b=c;(k∈Z and k=0)if a%b=c, then (k×a)%b=k×c%b;(k∈N∗)满足类似于分配律的等式(a+b)%c=((a%c)+(b%c))%c;(a×b)%c=((a%c)×(b%c))%c;
同余定理告诉我们可以“提早求余”,即: ( a × b × k ) % c (a \times b \times k) \% c (a×b×k)%c,我们先求得了 a a a和 b b b,就可以先求 a × b % c a\times b \% c a×b%c的结果,等 k k k得到后可以再求一次,不影响结果。
4.4 辗转相除法(欧几里得算法)
求a和b的最大公约数:
def fac(a: int,b: int)->int:
a,b = max(a,b),min(a,b)
while(a % b == 0):
t=a%b
a=b
b=t
return b
4.5 裴蜀定理(贝祖定理)
相关题目:365. 水壶问题
已知任何整数 a a a、 b b b和它们的最大公约数 d d d,则关于任何未知整数 x x x和 y y y的线性不定方程满足裴蜀等式: a , b ∈ Z , g c d ( a , b ) = d a,b \in Z,gcd(a,b)=d a,b∈Z,gcd(a,b)=d,那么对于任意整数 x , y , c ∈ Z x,y,c \in Z x,y,c∈Z,一定满足 a x + b y = c ⋅ d ax+by=c\cdot d ax+by=c⋅d。
即:若 a , b a,b a,b是整数,且 g c d ( a , b ) = d gcd(a,b)=d gcd(a,b)=d,那么对于任意的整数 x , y x,y x,y, a x + b y ax+by ax+by都一定是 d d d的倍数,特别地,一定存在整数 x , y x,y x,y,使 a x + b y = d ax+by=d ax+by=d成立。