用leetcode每日一题,
正好练一练python的一些写法吧
896.单调队列 判断数组是单增的或者是单减的
学习到一个sorted的用法,还有倒序的切片
class Solution:
def isMonotonic(self, A: List[int]) -> bool:
return sorted(A)==A or sorted(A)==A[::-1]
303.前缀和 两点作差
学习到list的append的用法
class NumArray:
def __init__(self, nums: List[int]):
self.sums = [0]
a = self.sums
for v in nums:
a.append(a[-1]+v)
def sumRange(self, i: int, j: int) -> int:
a = self.sums
return a[j+1]-a[i]
304.二维前缀和 区域求和
学习到二维list的初始化方法
class NumMatrix:
def __init__(self, matrix: List[List[int]]):
n, m = len(matrix), (len(matrix[0]) if matrix else 0)
self.ans = [[0]*(m+1) for _ in range (n+1)]
a = self.ans
for i in range(n):
for j in range(m):
a[i+1][j+1]=a[i+1][j]+a[i][j+1]-a[i][j]+matrix[i][j]
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
a = self.ans
return a[row2+1][col2+1]-a[row1][col2+1]-a[row2+1][col1]+a[row1][col1]
# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)
354.俄罗斯套娃问题 LIS变形
注意倒数第X个元素用-X即可,多用就会熟练一些
学习到list的sort方法,bisect的二分方法,bisect_left等价于lower_bound
class Solution:
def maxEnvelopes(self, envelopes: List[List[int]]) -> int:
n = len(envelopes)
envelopes.sort(key=lambda x:(x[0],-x[1]))
ans = [envelopes[0][1]]
for i in range(1,n):
num = envelopes[i][1]
if num > ans[-1]:
ans.append(num)
else:
pos = bisect.bisect_left(ans,num)
ans[pos] = num
return len(ans)
232.用栈实现队列
注意python没有stl对应栈和队列,所以用list来实现
not self.stack2对应非空,while self.stack1对应size>0,
pop()对应list的最后一个元素且弹出
发现自己之前的双栈实现队列都是暴力的,tx面试的时候写了个假的
实际上可以均摊,leetcode果然相对思维一些
class MyQueue:
def __init__(self):
self.stack1 = []
self.stack2 = []
"""
Initialize your data structure here.
"""
def push(self, x: int) -> None:
self.stack1.append(x)
"""
Push element x to the back of queue.
"""
def pop(self) -> int:
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop() if self.stack2 else None
"""
Removes the element from in front of queue and returns that element.
"""
def peek(self) -> int:
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2[-1] if self.stack2 else None
"""
Get the front element.
"""
def empty(self) -> bool:
return not self.stack1 and not self.stack2
"""
Returns whether the queue is empty.
"""
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
503. 下一个更大元素 II
单调栈,注意数组是循环的,巧妙的运用i%n
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
n = len(nums)
b = [-1]*(n)
stk = []
for i in range(2*n):
while stk and nums[stk[-1]]
131. 分割回文串
输出所有能把串分割成不同回文串的方案,
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
可以直接定义函数当成员,可以把list直接当元素用
extend用于合并两个list,相当于把另一个往一个里塞,
extend的作用与+号等同,但+会创建一个新的list,浪费内存
class Solution:
def partition(self, s: str) -> List[List[str]]:
self.isP = lambda s:s[::-1]==s
n = len(s)
ans = [[] for _ in range(n+1)]
for i in range(n):
for j in range(i+1):
if self.isP(s[j:i+1]):
if ans[j]:
ans[i+1].extend(list(map(lambda x:x+[s[j:i+1]],ans[j])))
else:
ans[i+1].append([s[j:i+1]])
return ans[n]
1784. 检查二进制字符串字段
判断01子串在不在给定的s里
class Solution:
def checkOnesSegment(self, s: str) -> bool:
return '01' not in s
class Solution:
def checkOnesSegment(self, s: str) -> bool:
return not s.count('01')
1785. 构成特定和需要添加的最少元素
对所有元素求和,可以用sum函数
class Solution:
def minElements(self, nums: List[int], limit: int, goal: int) -> int:
return (abs(goal-sum(nums))+limit-1)//limit
1786. 从第一个节点出发到最后一个节点的受限路径数
float('inf')与float('-inf'),分别是python里的正负无穷,
具体说明见:python中inf这个玩意_一只小鹰-CSDN博客_inf
关于dijkstra怎么用python写
可以参考heapq的用法:python高级(堆heapq模块)_jamfiy的博客-CSDN博客_python 堆
存图可以用邻接表的方式,也可以开n个dict,然后用邻接矩阵的形式
堆的库是heapq,heappush相当于push,其中第一维放入的q:list是需要维护堆序的list,
可以对值按增序维护,也可以对元组按增序维护,heappop(q)相当于弹出并获取q[0]的值
class Solution:
def countRestrictedPaths(self, n: int, edges: List[List[int]]) -> int:
e = [[] for _ in range(n)]
for u,v,w in edges:
u -= 1
v -= 1
e[u].append((v,w))
e[v].append((u,w))
dis = [1e18]*n
dis[n-1] = 0
q = []
vis = [False]*n
heapq.heappush(q,(dis[n-1],n-1))
while q:
d, u = heapq.heappop(q)
if vis[u]:
continue
vis[u] = True
for v,w in e[u]:
if dis[v] > dis[u] + w:
dis[v] = dis[u] + w
heapq.heappush(q,(dis[v],v))
a = [i for i in range(n)]
a.sort(key=lambda x:dis[x])
dp = [0]*n
dp[n-1] = 1
mod = 10**9+7
for u in a:
for v,w in e[u]:
if dis[v]>dis[u]:
dp[v] = (dp[v]+dp[u])%mod
return dp[0]
1787. 使所有区间的异或结果为零
求让每个长度为k的区间异或为0的时候,所需要改的最少的值的个数
注意到每k个一组,前k个定了,整个数组就定了,所以分组进行dp
min(las)用来返回las中最小的值
class Solution:
def minChanges(self, nums: list[int], k: int) -> int:
n = len(nums)
las = [2005]*(1<<10)
las[0] = 0
now = [2005]*(1<<10)
for i in range(k):
v = min(las)
cnt = defaultdict(int)
x = 0
for j in range(i,n,k):
x += 1
cnt[nums[j]] += 1
for j in range(1<<10):
now[j] = v + x
for a,b in cnt.items():
now[j] = min(now[j], las[j^a]+x-b)
now, las = las, now
return las[0]
C.Squared Error
怎么把字母'a'-'z'转成0-25
def cal(x):
return ord(x)-ord('a')
# ord代表字母转ascii
# chr代表ascii转字母
F.Digits Paradise in Hexadecimal
TODO: 补题
132. 分割回文串 II
①无论是python2还是python3,reversed(s)返回的类型都是reversed,不是str
而s[::-1]返回的类型是str,所以判断回文用str(reversed(s))==s或s[::-1]==s,后者更方便
②取子串的操作,类似list切片,比如取s[j]到s[i]的字符用s[j:i+1]即可
③判断变量类型,可以用type,例如type(reversed(s))
class Solution:
def minCut(self, s: str) -> int:
def isPalindrome(s):
return s[::-1]==s
n = len(s)
dp = [n]*(n+1)
dp[0] = 0
for i in range(n):
for j in range(i+1):
if isPalindrome(s[j:i+1]):
dp[i+1]=min(dp[i+1],dp[j]+1)
return dp[n]-1
224. 基本计算器
只有+,-和小括号的表达式求值,串长3e5
①isdigit()可以判断字符是不是数字
②eval(s)可以对表达式求值
s = "123+4"
print(eval(s))
for v in s:
if v.isdigit():
now = now * 10 + int(v)
227. 基本计算器 II
中间有多余空格,只有四则运算无小括号的表达式求值,除号当下取整用
①replace的用法,对str用
eval(s.replace('/','//'))
②去掉字符串内所有空格的奇技淫巧
s = ''.join(s.split())
B.CCA的搬运
例如,not in、insert和index的用法
n, m = map(int,input().split())
w = list(map(int,input().split()))
id = list(map(int,input().split()))
now = []
ans = 0
for v in id:
if v not in now:
now.insert(0,v)
pos = 0
else:
pos = now.index(v)
for j in range(pos+1,len(now)):
ans += w[now[j]-1]
now.pop(pos)
now.append(v)
print(ans)
C.CCA的子树
例如,global的用法
n = int(input())
w = list(map(int,input().split()))
e = [[] for _ in range(n)]
mx = [-2e18]*(n)
now = [0]*n
ans = -2e18
def dfs(u, fa):
global ans
now[u] = w[u]
for v in e[u]:
if v == fa:
continue
dfs(v, u)
ans = max(ans, mx[u]+mx[v])
mx[u] = max(mx[u], mx[v])
now[u] += now[v]
mx[u] = max(mx[u], now[u])
for i in range(1,n):
u, v = map(int,input().split())
u -= 1
v -= 1
e[u].append(v)
e[v].append(u)
dfs(0, -1)
if ans<-1e18:
print("Error")
else:
print(ans)
defaultdict允许直接访问下标,下标访问的值不存在时,返回的是工厂函数的默认值,
比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0
from collections import defaultdict
class MyHashSet:
def __init__(self):
"""
Initialize your data structure here.
"""
self.arr = defaultdict(int)
def add(self, key: int) -> None:
self.arr[key] = 1
def remove(self, key: int) -> None:
self.arr[key] = 0
def contains(self, key: int) -> bool:
return self.arr[key] == 1
"""
Returns true if this set contains the specified element
"""
54. 螺旋矩阵
给一个二维矩阵,输出螺旋填数的遍历顺序,
一个优雅写法是,控制当前运动向量为(dx,dy),则转向等价于顺时针转90度,变为(dy,-dx)
class Solution:
def spiralOrder(self, matrix):
n, m = len(matrix), len(matrix[0]) if matrix else 0
if not n or not m:
return []
ans, i, j, dx, dy = [], 0, 0, 0, 1
for _ in range(n*m):
ans.append(matrix[i][j])
matrix[i][j] = -101
if matrix[(i+dx)%n][(j+dy)%m] == -101:
dx, dy = dy, -dx
i, j = i+dx, j+dy
return ans
1791. 找出星型图的中心节点
给一个n>=3的菊花图(星型图)的n-1条边,找出中心点的点号
注意到前两个pair的交点即是答案,学习到了set求交,
set是不能按下标访问的,但是一个元素的set可以随机pop必中,所以可以采用以下写法:
class Solution:
def findCenter(self, edges: List[List[int]]) -> int:
return (set(edges[0]) & set(edges[1])).pop()
1792. 最大平均通过率
贪心+堆排的一道题,用heapq实现堆排,
辅助list内放入的,要么,是一个由两元素构成的tuple,会默认按第一维的值排增序
要么,是一个list,会按照list的每一维排增序
注意到sum,max这种聚合函数也是可以对for循环作嵌套的
class Solution:
def maxAverageRatio(self, classes: List[List[int]], extraStudents: int) -> float:
ans = []
import heapq
for u,v in classes:
heappush(ans, (-(1.0*(u+1)/(v+1)-1.0*u/v), (u,v)))
for i in range(extraStudents):
w, (u,v) = heappop(ans)
u, v = u+1, v+1
heappush(ans, (-(1.0*(u+1)/(v+1)-1.0*u/v), (u,v)))
return sum(u/v for _,(u,v) in ans)/len(ans)
1793. 好子数组的最大分数
单调栈裸题, 保证区间经过下标k即可
切片按nums[::-1]倒序遍历时,i还是增序的,
只是v是降序的,所以这个下标写的非常不舒服
class Solution:
def maximumScore(self, nums: List[int], k: int) -> int:
stk = []
n = len(nums)
l, r = [0]*n, [0]*n
for i,v in enumerate(nums):
while stk and nums[stk[-1]]>=v:
stk.pop()
l[i] = stk[-1]+1 if stk else 0
stk.append(i)
stk = []
for i,v in enumerate(nums[::-1]):
while stk and nums[stk[-1]]>=v:
stk.pop()
r[n-1-i] = stk[-1]-1 if stk else n-1
stk.append(n-1-i)
return max((r[i]-l[i]+1)*nums[i] for i in range(n) if l[i]<=k and k<=r[i])
150. 逆波兰表达式求值
仅包含加减乘除的合法逆波兰表达式求值,除为近零取整除
注意到python的向下取整除就是向下取整,-6/132为-1,6/(-132)也为-1,所以这种情况下刻意+1回来
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stk = []
for v in tokens:
if v in ('/','*','-','+'):
x, y = stk.pop(), stk.pop()
if v == '/':
stk.append(y//x + ((y%x)!=0 and (y//x)<0))
elif v == '*':
stk.append(y*x)
elif v == '+':
stk.append(y+x)
elif v == '-':
stk.append(y-x)
else:
stk.append(int(v))
return stk[-1]
lc双周赛待补题:力扣
atcoder待补题:abc195EF题
院赛待补题:线段树+SA+二进制枚举+倍增+杜教筛+弹弹球
5693. 字符串中第二大的数字
可以用set实现去重的功能,也可以排序之后遍历,但感觉不如这个方便
class Solution:
def secondHighest(self, s: str) -> int:
a = sorted(filter(lambda x: x>='0' and x<='9', list(set(s))))
return int(a[-2]) if len(a)>=2 else -1
191. 位1的个数
统计一个int在二进制表示下的1的个数
当然,可以采用i&(-i)的方式,统计lowbit,
但是,这里学的是怎么把int转成二进制,如下:
class Solution:
def hammingWeight(self, n: int) -> int:
return str(bin(n)).count('1')
于是,学到了bin(n)表示二进制,oct(n)表示十进制,hex(n)表示十六进制,如下:
>>> print(bin(5))
0b101
>>> print(oct(10))
0o12
>>> print(hex(22))
0x16
CodeJam资格赛的A题,
以下代码倒数第二行用于实现,
对列表一部分求逆序的功能
# 怎么翻转切片的一部分
t = int(input())
for ca in range(t):
n = int(input())
a = list(map(int,input().split()))
ans = 0
for i in range(n-1):
j = a.index(min(a[i:n]))
ans += j-i+1
a[i:j+1] = list(reversed(a[i:j+1]))
print(f"Case #{ca+1}: {ans}")
190. 颠倒二进制位
将一个无符号32位的数的32位二进制位,求逆序之后,对应的十进制数输出出来
int通过bin转二进制串,二进制串转回int
>>> bin(int('256', 10))
'0b100000000'
>>> str(int('0b100000000', 2))
'256'
以下函数,用来实现对拍,其中zfill是str的方法,
实现如果不到32位的话,在数字左边补0的功能
def test(self, n):
origin = bin(n).replace('0b','').zfill(32)
reverse = '0b'+origin[::-1]
ans = int(reverse,2)
return ans
装饰器的原理(带参数+带返回值+不带参数)
Python装饰器的通俗理解_LUOKai的博客-CSDN博客_装饰器python
1805. 字符串中不同整数的数目
一个串由字母和数字组成,将字母置换为空格,剩余的数去掉前导0,去重后输出数量
学习一个lstrip,是只用于修剪左边的;相对应的有rstrip
re.sub是正则,第一个参数是正则,第二个是替换为的串,第三维是操作的串str
class Solution:
def numDifferentIntegers(self, word: str) -> int:
return len(set(map(lambda x:x.lstrip('0'),re.sub('[a-z]',' ',word).split())))
还有一种做法,是找到所有的数字,\d指代数字0-9,+用于一个以上,可以参考findall的写法
Python--re模块的findall等用法 - Syw_文 - 博客园
class Solution:
def numDifferentIntegers(self, word: str) -> int:
return len(set(x.lstrip("0") for x in re.findall("\d+", word)))
264. 丑数 II
给你一个整数 n(1<=n<=1690)
,请你找出并返回第 n
个 丑数 。
丑数 就是只包含质因数 2
、3
和/或 5
的正整数。
考虑dp的做法,维护三指针2、3、5,表示当前指向的还没有更新其二倍、三倍、五倍的值的位置下标,
①dp[1]=1,且三指针2、3、5都指向0位置,必有一个的倍数是最小值,且三者无重复
②如果1到dp[i-1]都算好了,
且2、3、5都指向了还没有更新其二倍、三倍、五倍的值的位置下标,
即当前还没更新倍数的值的最小值,则更新三个最小值的2、3、5倍时,必有一个是最小值
且如果最小值等于其中若干个数的数的时候,让其中的指针一起往后挪动,避免了重复值被多次计数
①、②,dp[i]必由最小值转移而来,且避免了重复值被多次计数
class Solution:
def nthUglyNumber(self, n: int) -> int:
dp = [1]*n
p2 = p3 = p5 = 0
for i in range(1,n):
dp[i] = min(dp[p2]*2, dp[p3]*3, dp[p5]*5)
if dp[i] == dp[p2]*2:
p2 += 1
if dp[i] == dp[p3]*3:
p3 += 1
if dp[i] == dp[p5]*5:
p5 += 1
return dp[n-1]
179. 最大数
给定一组非负整数 nums
,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
考虑python3怎么按自定义比较排序:需要重载一个自定义的函数cmp,并塞进key=cmp_to_key(cmp)里去
或者写key=cmp_to_key(lambda x,y:int(y+x)-int(x+y))
# 如果小于0,x放在前面;如果大于0,x放在后面,可以认为是x-y,重载<号
from functools import cmp_to_key
class Solution:
def largestNumber(self, nums: List[int]) -> str:
if nums.count(0) == len(nums):
return '0'
nums = list(map(str, nums))
def cmp1(x, y):
return int(y+x)-int(x+y)
nums = sorted(nums, key=cmp_to_key(cmp1))
return ''.join(nums)
python3怎么枚举全排列,
需要from itertools import permutations
第一维放list/str,第二维放长度,可重集全排列会被多次枚举到
from functools import cmp_to_key
from itertools import permutations
import random
class Solution:
@classmethod
def largestNumber(self, nums):
if nums.count(0) == len(nums):
return '0'
nums = list(map(str, nums))
def cmp(x, y):
return int(y+x)-int(x+y)
nums = sorted(nums, key=cmp_to_key(cmp))
return ''.join(nums)
@classmethod
def test(self, nums):
if nums.count(0) == len(nums):
return '0'
nums = list(map(str, nums))
n = len(nums)
ans = ''
# 枚举全排列
for v in permutations(nums, n):
s = ''.join(v)
ans = s if ans == '' else max(ans, s)
return ans
if __name__ == "__main__":
nums = [0, 21, 23, 2, 87]
assert(Solution.largestNumber(nums) == Solution.test(nums))
nums = [0, 0, 0]
assert(Solution.largestNumber(nums) == Solution.test(nums))
for _ in range(100):
ans = [random.randint(0,10**9) for _ in range(1,10)]
assert(Solution.largestNumber(nums) == Solution.test(nums))
ord转ascii,chr再转换回去,遍历26个字母大概只能这样了
1832. 判断句子是否为全字母句
全字母句 指包含英语字母表中每个字母至少一次的句子。
class Solution:
def checkIfPangram(self, sentence: str) -> bool:
for i in range(26):
if chr(ord('a') + i) not in sentence:
return False
return True
5741. 最高建筑高度
lc的题都不会了,好羞耻,用c++写一发
考虑从前递推会从前边得到r的上界高度限制,从后递归会从后面得到r的高度限制,
然后讨论一下,最高高度是在某个限制处还是在两个限制之间
class Solution {
public:
int maxBuilding(int n, vector>& restrictions) {
if(!restrictions.size()){
return n-1;
}
sort(restrictions.begin(),restrictions.end());
int m=restrictions.size();
vectorl(m);
for(int i=0;i=0;--i){
l[i]=min(l[i],l[i+1]+restrictions[i+1][0]-restrictions[i][0]);
}
int ans=max(l[0],l[m-1]+n-restrictions[m-1][0]);
for(int i=0;i
137. 只出现一次的数字 II
给你一个整数数组 nums
,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
考虑三进制异或,二进制异或就是转成二进制然后对应位模2加,
所以,三进制异或是转成三进制然后对应位模3加
class Solution:
def singleNumber(self, nums: List[int]) -> int:
cnt = 0
for v in nums:
if v == 0:
cnt += 1
if cnt == 1:
return 0
sg = 0
res = 0
pw = [3**i for i in range(20)]
for v in nums:
if v<0:
sg = (sg+1)%3
v = abs(v)
for i in range(20):
a = res//pw[i]%3
b = v//pw[i]%3
c = (a+b)%3
res = res-a*pw[i]+c*pw[i]
if not sg:
return res
else:
return -res
python怎么对类排序,
重载functools的cmp_to_key方法,
如果,想让self放在前面的话就return -1,否则放在后面的话就return 1
python和c++在这个地方是不同的,只能考虑负数和正数,不能像bool那样返回01
import functools
def cmp(self, b):
if self.word > b.word:
return -1
elif self.word < b.word:
return 1
class Str():
def __init__(self, word):
self.word = word
class Solution:
def str_sort(self, words):
strs = [Str(word) for word in words]
strs.sort(key=functools.cmp_to_key(cmp))
return [s.word for s in strs]
a = Solution()
print(a.str_sort(['abc','zzz','xyz','abd']))
python的queue怎么实现,为了只访问头结点且不pop
自带的queue是用来多线程处理任务队列的,不方便,所以用deque
from collections import deque
a = deque()
a.append(5)
a.append(6)
print(a)
a.popleft()
a.appendleft(233)
print(a)
a.pop()
print(a)
python的heap里存字符串,怎么让字典序大的优先出队?
python的heap是小根堆,不是大根堆,很不方便,所以需要重载类,方法如下:
from heapq import *
class A:
def __init__(self, s):
self.s = s
def __lt__(self, other):
return self.s>other.s
a = A('abc')
b = A('bcd')
c = A('aa')
d = []
heappush(d, a)
heappush(d, b)
heappush(d, c)
print(heappop(d).s)
python实现set,set的二分查找
由于python的set和map都是无序的,所以需要引入内嵌用红黑树实现的SortedList
from sortedcontainers import SortedList
class Solution:
def reversePairs(self, A: List[int]) -> int:
d = SortedList()
ans = 0
for a in A:
ans += len(d) - d.bisect_right(2*a)
d.add(a)
return ans
lower()、upper()、capitalize()、title()、swapcase()
这几个方法分别用来:
将字符串转换为小写、大写字符串、将字符串首字母变为大写、将每个首字母变为大写以及大小写互换
class Solution(object):
def capitalizeTitle(self, a):
"""
:type title: str
:rtype: str
"""
ans = a.split(' ')
res = []
for v in ans:
if len(v) < 3:
v = v.lower()
else:
v = v.title()
res.append(v)
return ' '.join(res)
6009. 使两字符串互为字母异位词的最少步骤数
Counter,把串里的字母统计个数
from collections import Counter
class Solution:
def minSteps(self, s: str, t: str) -> int:
abc = "abcdefghijklmnopqrstuvwxyz"
c1 = Counter(s)
c2 = Counter(t)
res = 0
for a in abc:
res += abs(c1[a] - c2[a])
return res
>>> c = Counter('abcasd')
>>> c
Counter({'a': 2, 'c': 1, 'b': 1, 's': 1, 'd': 1})
colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
c = Counter(colors)
print (dict(c))