LeetCode刷题小技巧(Python版)

本文不定期更新

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=8106<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. 统计出现过一次的公共字符串为例,题目是:给你两个字符串数组 words1words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。

这时我们就可以用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库有三个函数:bisectbisect_rightbisect_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
###

其中bisectbisect_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 ab=cac=bcb=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;(kZ and k=0)if a%b=c, then (k×a)%b=k×c%b;(kN)满足类似于分配律的等式(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,bZgcd(a,b)=d,那么对于任意整数 x , y , c ∈ Z x,y,c \in Z x,y,cZ,一定满足 a x + b y = c ⋅ d ax+by=c\cdot d ax+by=cd

即:若 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成立。

  • 18
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: LeetCode 是一个在线编程挑战网站,提供了许多算法和数据结构题目供程序员练习和提高。下面是一些关于使用 PythonLeetCode 的提示: 1. 首先,了解题目的要求和限制,并确定解题思路。 2. 使用自己熟悉的编程语言(如 Python)进行编码。 3. 在完成编码后,进行单元测试,确保代码的正确性。 4. 提交代码,查看结果。如果错误,请思考错误原因并进行调试。 5. 反复做题,提高自己的算法和数据结构能力。 6. 可以参考其他人的题解和代码,可以更好的学习和了解题目的解法。 ### 回答2: LeetCode是一款非常好的刷题平台,它提供了大量的算法题目,帮助程序员们提高编程技能。但是,想要刷好LeetCode需要一些方法和技巧。本篇文章主要介绍LeetCode刷题指南,特别是使用Python语言刷题。 首先,我们需要明确一个问题:刷LeetCode最重要的是什么?我认为是“理解算法”。很多人最开始刷LeetCode时会想直接写代码试试,这是错误的做法。我们首先需要理解题目的意思,思考算法的解题思路,以及算法的时间复杂度和空间复杂度等问题。只有当我们弄懂了算法的思路,才能够写出高质量的代码。 其次,我们需要建立良好的代码习惯。Python是一门非常简洁优雅的语言,但是我们需要注意代码的可读性和规范性,这样在后期维护代码时会更加方便。建议使用pycharm等IDE工具,并安装Pylint等插件进行代码检查和优化。 接下来,我们需要准备好一些有效的刷题工具。为了方便,我们可以在本地安装刷题必备工具,例如:leetcode-cli、leetcode vscode插件、leetcode-cn的官方Python SDK等。这些工具可以帮助我们快速地创建、调试和提交题解,并且可以方便地查看题目和测试样例。另外,我们还可以用一些在线的工具,如Jupyter Notebook、Google Colab等来刷题。 最后,我们需要保持耐心和持之以恒的心态。LeetCode刷题不是一蹴而就的事情,需要坚持不懈地努力。每道题都应该认真思考,从简单到复杂、从容易到难以深入理解,跟着题目一步步实现代码解题。通过刷题,我们可以锻炼自己的编程技能、提高算法水平、积累自己的编程经验。 总之,LeetCode是一款非常优秀的算法题目平台,它可以帮助程序员们提高编程水平。使用Python语言刷题,需要我们掌握好编程思路,建立好良好的代码习惯,使用好刷题工具,并坚持不懈地刷题去提升自己的能力。 ### 回答3: 随着人工智能和大数据技术的快速发展,编程成为了一项越来越重要的技能。而刷leetcode算法题是提高编程技能、增加算法思维的有力方式之一。本文主要介绍如何通过Python语言刷leetcode算法题。 一、准备工作 1.安装Python环境 Python是一种优秀的面向对象的解释型计算机程序设计语言,在如今的人工智能和数据科学领域应用广泛。首先需要安装Python环境,推荐安装本为Python 3.x。 2.注册LeetCode账号 可以通过该网站进行LeetCode算法刷题,而注册账号是必选步骤。 二、解题流程 1.题目分析:初学者可先从LeetCode官方题解中找到简单难度的题目,通过阅读题目,明确题目的意义,梳理解题思路和关键信息。 2.思路整理:理清题目后,可以尝试使用笔和纸来将题目要求和信息进行抽象和总结。可以画图或列出清晰的步骤,为编写代码提供思路。 3.编写代码:将思路转化为代码实现。结合算法,通过Python语言的面向对象编程,从而完成代码的编写。 4.测试和优化:在完成编码后,需要对代码进行测试,并对代码进行优化处理。可以通过LeetCode的自动评测系统,检查代码运行是否正确。此步骤也有助于人为地检查代码中的错误,提高代码的效率和质量。 5.总结归纳:在完成一定数量的算法刷题后,可以对做题有所总结和归纳。思考算法题的分类和解题的技巧,这有助于加深理解并提高解题效率。 三、学习资源 1. LeetCode官方网站:www.leetcode.com 2. 《Python Algorithm Interview》 3. 《算法图解》 4. 数字图书馆:https://www.gitbook.com/book/jalan/leetcode-python/details 5. Github仓库:https://github.com/yuzhoujr/leetcode-python 总结一下,刷LeetCode题目是提高自己的算法和编程能力的好方法,Python语言无疑是实现目标的好选择;同时,在刷题过程中,理清题目并充分思考,多测试,总结归纳同样重要。希望以上的介绍有助于您更好地学习和刷题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值