给定一个嵌套的整数列表 nestedList ,每个元素要么是整数,要么是列表。同时,列表中元素同样也可以是整数或者是另一个列表。
整数的 深度 是其在列表内部的嵌套层数。例如,嵌套列表 [1,[2,2],[[3],2],1] 中每个整数的值就是其深度。
请返回该列表按深度加权后所有整数的总和。
链接:https://leetcode.cn/problems/nested-list-weight-sum
# """
# This is the interface that allows for creating nested lists.
# You should not implement it, or speculate about its implementation
# """
#class NestedInteger:
# def __init__(self, value=None):
# """
# If value is not specified, initializes an empty list.
# Otherwise initializes a single integer equal to value.
# """
#
# def isInteger(self):
# """
# @return True if this NestedInteger holds a single integer, rather than a nested list.
# :rtype bool
# """
#
# def add(self, elem):
# """
# Set this NestedInteger to hold a nested list and adds a nested integer elem to it.
# :rtype void
# """
#
# def setInteger(self, value):
# """
# Set this NestedInteger to hold a single integer equal to value.
# :rtype void
# """
#
# def getInteger(self):
# """
# @return the single integer that this NestedInteger holds, if it holds a single integer
# Return None if this NestedInteger holds a nested list
# :rtype int
# """
#
# def getList(self):
# """
# @return the nested list that this NestedInteger holds, if it holds a nested list
# Return None if this NestedInteger holds a single integer
# :rtype List[NestedInteger]
# """
class Solution:
def depthSum(self, nestedList: List[NestedInteger]) -> int:
dic1 = []
dic2 = []
def dfs(l, depth):
for x in l:
if x.isInteger():
dic1.append(x.getInteger())
dic2.append(depth)
else:
dfs(x.getList(), depth+1)
dfs(nestedList, 1)
ans = 0
for x, y in zip(dic1, dic2):
ans += (x*y)
return ans
请在 n × n 的棋盘上,实现一个判定井字棋(Tic-Tac-Toe)胜负的神器,判断每一次玩家落子后,是否有胜出的玩家。
在这个井字棋游戏中,会有 2 名玩家,他们将轮流在棋盘上放置自己的棋子。
在实现这个判定器的过程中,你可以假设以下这些规则一定成立:
1. 每一步棋都是在棋盘内的,并且只能被放置在一个空的格子里;
2. 一旦游戏中有一名玩家胜出的话,游戏将不能再继续;
3. 一个玩家如果在同一行、同一列或者同一斜对角线上都放置了自己的棋子,那么他便获得胜利。
链接:https://leetcode.cn/problems/design-tic-tac-toe
class TicTacToe:
def __init__(self, n: int):
# inf = 2*31 - 1
self.keyboard = [['' for _ in range(n)] for _ in range(n)]
self.n = n
self.dic1_r = defaultdict(int)
self.dic1_c = defaultdict(int)
self.dic1_w = 0
self.dic1_u = 0
self.dic2_r = defaultdict(int)
self.dic2_c = defaultdict(int)
self.dic2_w = 0
self.dic2_u = 0
def move(self, row: int, col: int, player: int) -> int:
if player == 1:
self.keyboard[row][col] = 'X'
self.dic1_r[row] += 1
self.dic1_c[col] += 1
if row == col:
self.dic1_w+=1
if row == self.n-col-1:
self.dic1_u+=1
if self.dic1_r[row] == self.n or self.dic1_c[col] == self.n:
return 1
if self.dic1_w==self.n or self.dic1_u == self.n:
return 1
return 0
else:
self.keyboard[row][col] = 'O'
self.dic2_r[row] += 1
self.dic2_c[col] += 1
if row == col:
self.dic2_w+=1
if row == self.n-col-1:
self.dic2_u+=1
if self.dic2_r[row] == self.n or self.dic2_c[col] == self.n:
return 2
if self.dic2_w==self.n or self.dic2_u == self.n:
return 2
return 0
return 0
# Your TicTacToe object will be instantiated and called as such:
# obj = TicTacToe(n)
# param_1 = obj.move(row,col,player)
给你一个已经 排好序 的整数数组 nums 和整数 a 、 b 、 c 。对于数组中的每一个元素 nums[i] ,计算函数值 f(x) = ax2 + bx + c ,请 按升序返回数组 。
链接:https://leetcode.cn/problems/sort-transformed-array
class Solution:
def sortTransformedArray(self, nums: List[int], a: int, b: int, c: int) -> List[int]:
ans = []
### 一元一次方程
if a == 0:
for i,x in enumerate(nums):
tmp = a*(x**2) + b*x + c
ans.append(tmp)
if b>0:
return ans
### 常数
elif b==0:
return [c]*len(nums)
else:
return ans[::-1]
l = -(b/(2*a))
idx = -1
minm = float("inf")
for i,x in enumerate(nums):
if abs(x-l) < minm:
idx = i
minm = abs(x-l)
left, right = idx-1, idx+1
while left >= 0 and right <= len(nums)-1:
tmp = a*(nums[idx]**2) + b*nums[idx] + c
ans.append(tmp)
if abs(nums[left]-l) > abs(nums[right]-l):
idx = right
right += 1
else:
idx = left
left -= 1
tmp = a*(nums[idx]**2) + b*nums[idx] + c
ans.append(tmp)
if left != -1:
for i in range(left,-1,-1):
tmp = a*(nums[i]**2) + b*nums[i] + c
ans.append(tmp)
if right != len(nums) :
for i in range(right, len(nums)):
tmp = a*(nums[i]**2) + b*nums[i] + c
ans.append(tmp)
if a>0:
return ans
else:
return ans[::-1]
设计一个敲击计数器,使它可以统计在过去 5 分钟内被敲击次数。(即过去 300 秒)
您的系统应该接受一个时间戳参数 timestamp (单位为 秒 ),并且您可以假定对系统的调用是按时间顺序进行的(即 timestamp 是单调递增的)。几次撞击可能同时发生。
实现 HitCounter 类:
HitCounter() 初始化命中计数器系统。
void hit(int timestamp) 记录在 timestamp ( 单位为秒 )发生的一次命中。在同一个 timestamp 中可能会出现几个点击。
int getHits(int timestamp) 返回 timestamp 在过去 5 分钟内(即过去 300 秒)的命中次数。
链接:https://leetcode.cn/problems/design-hit-counter
class HitCounter:
def __init__(self):
self.times = defaultdict(int)
self.time = []
self.left = 0
self.right = 0
def hit(self, timestamp: int) -> None:
if timestamp not in self.time:
self.time.append(timestamp)
while timestamp - self.time[self.left] >= 300:
self.left += 1
self.times[timestamp] += 1
def getHits(self, timestamp: int) -> int:
print(self.left, self.time)
if timestamp not in self.time:
while self.left<len(self.time) and timestamp - self.time[self.left] >= 300:
self.left += 1
ans = 0
for i in range(self.left, len(self.time)):
ans += self.times[self.time[i]]
return ans
# Your HitCounter object will be instantiated and called as such:
# obj = HitCounter()
# obj.hit(timestamp)
# param_2 = obj.getHits(timestamp)
给你一个大小为 m x n 的矩阵 grid ,其中每个单元格都放置有一个字符:
'W' 表示一堵墙
'E' 表示一个敌人
'0'(数字 0)表示一个空位
返回你使用 一颗炸弹 可以击杀的最大敌人数目。你只能把炸弹放在一个空位里。
由于炸弹的威力不足以穿透墙体,炸弹只能击杀同一行和同一列没被墙体挡住的敌人。
链接:https://leetcode.cn/problems/bomb-enemy
class Solution:
def maxKilledEnemies(self, grid: List[List[str]]) -> int:
m, n = len(grid), len(grid[0])
self.res = 0
### 超时
# for i in range(m):
# for j in range(n):
# if grid[i][j] == '0':
# pathway = [(1,0),(0,1),(-1,0),(0,-1)]
# num = 0
# for k in range(4):
# dr, dc = pathway[k]
# nr, nc = i+dr, j+dc
# while 0<=nr
# if grid[nr][nc] == 'E':
# num+=1
# nr += dr
# nc += dc
# self.res = max(self.res, num)
# return self.res
f_r = [[-1 for _ in range(n)] for _ in range(m)]
f_c = [[-1 for _ in range(n)] for _ in range(m)]
for i in range(m):
for j in range(n):
if grid[i][j] == '0':
if i==0 or f_r[i-1][j]==-1:
pathway = [(1,0),(-1,0)]
num = 0
for k in range(2):
dr, dc = pathway[k]
nr, nc = i+dr, j+dc
while 0<=nr<m and 0<=nc<n and grid[nr][nc]!='W':
if grid[nr][nc] == 'E':
num+=1
nr += dr
nc += dc
f_r[i][j] = num
else:
f_r[i][j] = f_r[i-1][j]
if j==0 or f_c[i][j-1] == -1:
pathway = [(0,1),(0,-1)]
num = 0
for k in range(2):
dr, dc = pathway[k]
nr, nc = i+dr, j+dc
while 0<=nr<m and 0<=nc<n and grid[nr][nc]!='W':
if grid[nr][nc] == 'E':
num+=1
nr += dr
nc += dc
f_c[i][j] = num
else:
f_c[i][j] = f_c[i][j-1]
self.res = max(self.res, f_r[i][j]+f_c[i][j])
return self.res
给你一个整数嵌套列表 nestedList ,每一个元素要么是一个整数,要么是一个列表(这个列表中的每个元素也同样是整数或列表)。
整数的 深度 取决于它位于多少个列表内部。例如,嵌套列表 [1,[2,2],[[3],2],1] 的每个整数的值都等于它的 深度 。令 maxDepth 是任意整数的 最大深度 。
整数的 权重 为 maxDepth - (整数的深度) + 1 。
将 nestedList 列表中每个整数先乘权重再求和,返回该加权和。
链接:https://leetcode.cn/problems/nested-list-weight-sum-ii
# """
# This is the interface that allows for creating nested lists.
# You should not implement it, or speculate about its implementation
# """
#class NestedInteger:
# def __init__(self, value=None):
# """
# If value is not specified, initializes an empty list.
# Otherwise initializes a single integer equal to value.
# """
#
# def isInteger(self):
# """
# @return True if this NestedInteger holds a single integer, rather than a nested list.
# :rtype bool
# """
#
# def add(self, elem):
# """
# Set this NestedInteger to hold a nested list and adds a nested integer elem to it.
# :rtype void
# """
#
# def setInteger(self, value):
# """
# Set this NestedInteger to hold a single integer equal to value.
# :rtype void
# """
#
# def getInteger(self):
# """
# @return the single integer that this NestedInteger holds, if it holds a single integer
# Return None if this NestedInteger holds a nested list
# :rtype int
# """
#
# def getList(self):
# """
# @return the nested list that this NestedInteger holds, if it holds a nested list
# Return None if this NestedInteger holds a single integer
# :rtype List[NestedInteger]
# """
class Solution:
def depthSumInverse(self, nestedList: List[NestedInteger]) -> int:
self.depth = []
self.nums = []
def dfs(i, x, dist):
l = x.getList()
for j,y in enumerate(l):
if y.isInteger():
self.depth.append(dist)
self.nums.append(y.getInteger())
elif y.getList() == []:
self.depth.append(dist)
self.nums.append(0)
else:
dfs(i+j, y, dist+1)
for i,x in enumerate(nestedList):
dp = 1
if not x.isInteger():
# if x.getList() != []:
dfs(i, x, dp+1)
else:
self.depth.append(dp)
self.nums.append(x.getInteger())
if self.depth == []: return 0
max_depth = max(self.depth)
res = 0
for i in range(len(self.depth)):
res += (max_depth-self.depth[i]+1)*self.nums[i]
print(self.depth, self.nums)
return res
设计一个电话目录管理系统,让它支持以下功能:
get: 分配给用户一个未被使用的电话号码,获取失败请返回 -1 check: 检查指定的电话号码是否被使用 release:
释放掉一个电话号码,使其能够重新被分配
链接:https://leetcode.cn/problems/design-phone-directory
class PhoneDirectory:
def __init__(self, maxNumbers: int):
self.dic = defaultdict(int)
for i in range(maxNumbers):
self.dic[i] = 0
def get(self) -> int:
for k, v in self.dic.items():
if v == 0:
self.dic[k] = 1
return k
return -1
def check(self, number: int) -> bool:
if self.dic[number]==0:
return True
else:
return False
def release(self, number: int) -> None:
self.dic[number] = 0
# Your PhoneDirectory object will be instantiated and called as such:
# obj = PhoneDirectory(maxNumbers)
# param_1 = obj.get()
# param_2 = obj.check(number)
# obj.release(number)
在一个二维平面空间中,给你 n 个点的坐标。问,是否能找出一条平行于 y 轴的直线,让这些点关于这条直线成镜像排布?
注意:题目数据中可能有重复的点。
class Solution:
def isReflected(self, points: List[List[int]]) -> bool:
def sorted_cmp(l1, l2):
if l1[0] > l2[0]:
return 1
elif l1[0] == l2[0]:
if l1[1] > l2[1]:
return 1
else:
return -1
else:
return -1
points.sort(key = cmp_to_key(sorted_cmp))
arr = []
for k in points:
if k not in arr:
arr.append(k)
points = arr
if len(points)%2 == 0:
x = 0
for l in points:
x += l[0]
x = x/len(points)
i, j = 0, len(points)//2
flag = True
while i < (len(points)//2) and j < (len(points)):
# print(i, j, points, x)
if points[i][0] == points[j][0] == x:
flag = True
elif points[i][1] != points[j][1] or x-points[i][0] != points[j][0]-x:
flag = False
break
i+=1
j+=1
if flag:
return True
flag = True
i, j = 0, len(points)-1
while i < (len(points)//2) and j > (len(points)//2 -1):
# print(flag, points, x)
if points[i][0] == points[j][0] == x:
flag = True
elif points[i][1] != points[j][1] or x-points[i][0] != points[j][0]-x:
flag = False
break
i+=1
j-=1
if flag:
return True
return False
else:
x = points[len(points)//2][0]
i, j = 0, len(points)//2+1
flag = True
while i < (len(points)//2) and j < (len(points)):
if points[i][0] == points[j][0] == x:
flag = True
elif points[i][1] != points[j][1] or x-points[i][0] != points[j][0]-x:
flag = False
break
i+=1
j+=1
if flag:
return True
flag = True
i, j = 0, len(points)-1
while i < (len(points)//2) and j > (len(points)//2):
if points[i][0] == points[j][0] == x:
flag = True
elif points[i][1] != points[j][1] or x-points[i][0] != points[j][0]-x:
flag = False
break
i+=1
j-=1
if flag:
return True
return False
class Solution:
def numberOfPatterns(self, m: int, n: int) -> int:
dic = {
1 : {3,7,9},
2 : {8},
3 : {1,9,7},
4 : {6},
5 : {},
6 : {4},
7 : {1, 9, 3},
8 : {2},
9 : {3, 7, 1}
}
self.res = 0
visited = [False for _ in range(9)]
def check(arr):
if len(arr) == 1:
return True
for i in range(0,len(arr)-1):
x = arr[i]
y = arr[i+1]
if y in dic[x]:
mid = (x + y)//2
if mid not in arr[:i]:
return False
return True
def backtrace(x, path):
if x>=n+1:
return
if not check(path):
return
if x>=m and x<=n:
self.res += 1
for i in range(9):
if not visited[i]:
visited[i] = True
backtrace(x+1, path+[i+1])
visited[i] = False
for i in range(9):
visited[i] = True
backtrace(1, [i+1])
visited[i] = False
return self.res
给定二叉树的根 root ,返回树中最长连续路径的长度。
连续路径是路径中相邻节点的值相差 1 的路径。此路径可以是增加或减少。
例如, [1,2,3,4] 和 [4,3,2,1] 都被认为有效,但路径 [1,2,4,3] 无效。
另一方面,路径可以是子-父-子顺序,不一定是父子顺序。
链接:https://leetcode.cn/problems/binary-tree-longest-consecutive-sequence-ii
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def longestConsecutive(self, root: Optional[TreeNode]) -> int:
if not root: return 0
self.res = 1
def dfs(root):
if not root: return (0, 0)
left, right = dfs(root.left), dfs(root.right)
inc = dec = 1
if root.left:
if root.left.val == root.val + 1:
inc += left[0]
elif root.left.val == root.val - 1:
dec += left[1]
if root.right:
if root.right.val == root.val + 1:
inc = max(inc, right[0] + 1)
elif root.right.val == root.val - 1:
dec = max(dec, right[1] + 1)
self.res = max(self.res, inc + dec - 1)
return (inc, dec)
dfs(root)
return self.res
给定一棵二叉搜索树和其中的一个节点 node ,找到该节点在树中的中序后继。如果节点没有中序后继,请返回 null 。
一个节点 node 的中序后继是键值比 node.val 大所有的节点中键值最小的那个。
你可以直接访问结点,但无法直接访问树。每个节点都会有其父节点的引用。节点 Node 定义如下:
class Node {
public int val;
public Node left;
public Node right;
public Node parent;
}
链接:https://leetcode.cn/problems/inorder-successor-in-bst-ii
"""
# Definition for a Node.
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
self.parent = None
"""
class Solution:
def inorderSuccessor(self, node: 'Node') -> 'Optional[Node]':
###两种情况
if node.right:
node = node.right
while node.left:
node = node.left
return node
while node.parent and node == node.parent.right:
node = node.parent
return node.parent
给定一个二进制数组 nums ,如果最多可以翻转一个 0 ,则返回数组中连续 1 的最大个数。
class Solution:
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
f = [[0,0] for _ in range(len(nums))]
if nums[0] == 1:
f[0][1] = 1
f[0][0] = 0
else:
f[0][1] = 0
f[0][0] = 1
idx = 1
res = 1
while idx < len(nums):
if nums[idx]==1:
f[idx][0] = f[idx-1][0] + 1
f[idx][1] = f[idx-1][1] + 1
if nums[idx] == 0:
f[idx][0] = f[idx-1][1] + 1
f[idx][1] = 0
res = max(res,f[idx][0],f[idx][1])
idx += 1
return res
给定一个表示任意嵌套三元表达式的字符串 expression ,求值并返回其结果。
你可以总是假设给定的表达式是有效的,并且只包含数字, ‘?’ , ‘:’ , ‘T’ 和 ‘F’ ,其中 ‘T’ 为真, ‘F’ 为假。表达式中的所有数字都是 一位 数(即在 [0,9] 范围内)。
条件表达式从右到左分组(大多数语言中都是这样),表达式的结果总是为数字 ‘T’ 或 ‘F’ 。
链接:https://leetcode.cn/problems/ternary-expression-parser
class Solution:
def parseTernary(self, expression: str) -> str:
st = []
is_flag = False
for i in range(len(expression)-1, -1, -1):
if expression[i] == ':':
continue
elif expression[i] == '?':
is_flag = True
else:
if is_flag:
if expression[i] == 'T':
res = st[-1]
st.pop()
st.pop()
st.append(res)
else:
st.pop()
is_flag = False
else:
st.append(expression[i])
return st[0]
在 NBA 季后赛中,我们总是安排较强的队伍对战较弱的队伍,例如用排名第 1 的队伍和第 n 的队伍对决,这是一个可以让比赛更加有趣的好策略。现在,给你 n 支队伍,你需要以字符串格式输出它们的 最终 比赛配对。
n 支队伍按从 1 到 n 的正整数格式给出,分别代表它们的初始排名(排名 1 最强,排名 n 最弱)。我们用括号(‘(’, ‘)’)和逗号(‘,’)来表示匹配对——括号(‘(’, ‘)’)表示匹配,逗号(‘,’)来用于分割。 在每一轮的匹配过程中,你都需要遵循将强队与弱队配对的原则。
链接:https://leetcode.cn/problems/output-contest-matches
class Solution(object):
def findContestMatch(self, n):
team = [str(x) for x in range(1, n + 1)]
while n > 1:
for i in range(n // 2):
team[i] = "({},{})".format(team[i], team[n-i-1])
n //= 2
return team[0]
由范围 [1,n] 内所有整数组成的 n 个整数的排列 perm 可以表示为长度为 n - 1 的字符串 s ,其中:
如果 perm[i] < perm[i + 1] ,那么 s[i] == ’ i ’
如果 perm[i] > perm[i + 1] ,那么 s[i] == ‘D’ 。
给定一个字符串 s ,重构字典序上最小的排列 perm 并返回它。
链接:https://leetcode.cn/problems/find-permutation
class Solution:
def findPermutation(self, s: str) -> List[int]:
### DFS
# n = len(s) + 1
# self.res = []
# visited = [False for _ in range(n)]
# def dfs(arr, idx):
# if self.res != []:
# return
# if len(arr)==n:
# self.res = (arr)
# return
# if idx >= n-1:
# return
# for x in range(1,n+1):
# if s[idx] == 'I' and not visited[x-1] and x>(arr[-1]):
# visited[x-1] = True
# dfs(arr+[(x)], idx+1)
# visited[x-1] = False
# if s[idx] == 'D' and not visited[x-1] and x<(arr[-1]):
# visited[x-1] = True
# dfs(arr+[(x)], idx+1)
# visited[x-1] = False
# for i in range(1, n+1):
# visited[i-1] = True
# dfs([(i)], 0)
# if self.res != []:
# break
# visited[i-1] = False
# return (self.res)
### dp 不超时
n = len(s)
nums = list(range(1, n+2))
pre = s[0]
cnt = 1
for i in range(1, n):
if pre == s[i]:
cnt += 1
else:
if pre == 'D':
nums[i-cnt:i+1] = nums[i-cnt:i+1][::-1]
pre = s[i]
cnt = 1
if pre == 'D':
nums[n-cnt:n+1] = nums[n-cnt:n+1][::-1]
return nums
给定一个字符串列表 strs,你可以将这些字符串连接成一个循环字符串,对于每个字符串,你可以选择是否翻转它。在所有可能的循环字符串中,你需要分割循环字符串(这将使循环字符串变成一个常规的字符串),然后找到字典序最大的字符串。
具体来说,要找到字典序最大的字符串,你需要经历两个阶段:
将所有字符串连接成一个循环字符串,你可以选择是否翻转某些字符串,并按照给定的顺序连接它们。
在循环字符串的某个位置分割它,这将使循环字符串从分割点变成一个常规的字符串。
你的工作是在所有可能的常规字符串中找到字典序最大的一个。
链接:https://leetcode.cn/problems/split-concatenated-strings
class Solution:
def splitLoopedString(self, strs: List[str]) -> str:
### Limted time exceed
# arr = []
# res = ''
# for s in strs:
# tmp = arr
# arr = []
# s1 = s
# s2 = s[::-1]
# if tmp == []:
# arr = [s1,s2]
# else:
# for x in tmp:
# arr.append(x+s1)
# arr.append(x+s2)
# for x in arr:
# for i in range(len(x)):
# res = max(res, x[i:] + x[:i])
# return (res)
####
arr = [s if s>s[::-1] else s[::-1] for s in strs]
res = ''.join(arr)
for i in range(len(arr)):
other = ''.join(arr[i+1:]) + ''.join(arr[:i])
for j in range(len(arr[i])):
head = arr[i][:j]
tail = arr[i][j:]
cur = tail + other + head
res = max(cur, res)
cur = head[::-1] + other + tail[::-1]
res = max(cur, res)
return res
现在有一棵树,一只松鼠和一些坚果。位置由二维网格的单元格表示。你的目标是找到松鼠收集所有坚果的最小路程,且坚果是一颗接一颗地被放在树下。松鼠一次最多只能携带一颗坚果,松鼠可以向上,向下,向左和向右四个方向移动到相邻的单元格。移动次数表示路程。
链接:https://leetcode.cn/problems/squirrel-simulation
class Solution:
def minDistance(self, height: int, width: int, tree: List[int], squirrel: List[int], nuts: List[List[int]]) -> int:
path = float('inf')
x, y = squirrel
x_t, y_t = tree
path_t = 0
for i, j in nuts:
cur = abs(i-x_t) + abs(j-y_t)
path_t += cur*2
for i,j in nuts:
cur = path_t - (abs(i-x_t) + abs(j-y_t)) + (abs(i-x) + abs(j-y))
path = min(path, cur)
return path
在组合数学中,如果一个排列中所有元素都不在原先的位置上,那么这个排列就被称为 错位排列 。
给定一个从 1 到 n 升序排列的数组,返回 不同的错位排列 的数量 。由于答案可能非常大,你只需要将答案对 109+7 取余 输出即可。
链接:https://leetcode.cn/problems/find-the-derangement-of-an-array
class Solution:
def findDerangement(self, n: int) -> int:
f = [0 for _ in range(n+1)]
f[0] = 0
f[1] = 1
for i in range(2, n+1):
f[i] = (i)*(f[i-1] + f[i-2]) % 1000000007
return f[n-1]
在 X-Y 平面上表示的校园中,有 n 名工人和 m 辆自行车,其中 n <= m。
给定一个长度为 n 的数组 workers ,其中 worker [i] = [xi, yi] 表示第 i 个工人的位置。你也得到一个长度为 m 的自行车数组 bikers ,其中 bikes[j] = [xj, yj] 是第 j 辆自行车的位置。所有给定的位置都是 唯一 的。
我们需要为每位工人分配一辆自行车。在所有可用的自行车和工人中,我们选取彼此之间 曼哈顿距离 最短的工人自行车对 (workeri, bikej) ,并将其中的自行车分配給工人。
如果有多个 (workeri, bikej) 对之间的 曼哈顿距离 相同,那么我们选择 工人索引最小 的那对。类似地,如果有多种不同的分配方法,则选择 自行车索引最小 的一对。不断重复这一过程,直到所有工人都分配到自行车为止。
返回长度为 n 的向量 answer,其中 answer[i] 是第 i 位工人分配到的自行车的索引(从 0 开始)。
给定两点 p1 和 p2 之间的 曼哈顿距离 为 Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|。
链接:https://leetcode.cn/problems/campus-bikes
class Solution:
def assignBikes(self, workers: List[List[int]], bikes: List[List[int]]) -> List[int]:
def Manhattan(p1, p2):
return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
from sortedcontainers import SortedDict as SD
dic = SD()
for i,b in enumerate(workers):
for j,w in enumerate(bikes):
dist = Manhattan(b, w)
if dist not in dic:
dic[dist] = [(i,j)]
else:
dic[dist].append((i, j))
res = [0 for _ in range(len(workers))]
visited_b = [False for _ in range(len(bikes))]
visited_w = [False for _ in range(len(workers))]
cnt = 0
for k, v in dic.items():
for x in v:
i, j = x
if not visited_w[i] and not visited_b[j]:
visited_w[i] = True
visited_b[j] = True
res[i] = j
cnt+=1
if cnt == len(workers):
break
return res
由空地和墙组成的迷宫中有一个球。球可以向上下左右四个方向滚动,但在遇到墙壁前不会停止滚动。当球停下时,可以选择下一个方向。
给定球的起始位置,目的地和迷宫,找出让球停在目的地的最短距离。距离的定义是球从起始位置(不包括)到目的地(包括)经过的空地个数。如果球无法停在目的地,返回 -1。
迷宫由一个0和1的二维数组表示。 1表示墙壁,0表示空地。你可以假定迷宫的边缘都是墙壁。起始位置和目的地的坐标通过行号和列号给出。
链接:https://leetcode.cn/problems/the-maze-ii
class Solution:
def shortestDistance(self, maze: List[List[int]], start: List[int], destination: List[int]) -> int:
queue = [(start[0], start[1])]
m, n = len(maze), len(maze[0])
dist = [[float('inf') for _ in range(n)]for _ in range(m)]
dist[start[0]][start[1]] = 0
while queue:
cur_i, cur_j = queue.pop(0)
print(cur_i, cur_j)
pathway = [(1,0),(-1,0),(0,1),(0,-1)]
for i in range(4):
dr, dc = pathway[i]
nr, nc = cur_i+dr, cur_j+dc
step = 1
while 0<=nr<m and 0<=nc<n and maze[nr][nc]==0:
nr += dr
nc += dc
step += 1
nr -= dr
nc -= dc
step -= 1
if dist[nr][nc]>dist[cur_i][cur_j]+step:
dist[nr][nc] = dist[cur_i][cur_j]+step
queue.append((nr, nc))
if dist[destination[0]][destination[1]] == float('inf'):
return -1
else:
return dist[destination[0]][destination[1]]
给你一个大小为 m x n 的二维字符数组 picture ,表示一张黑白图像,数组中的 ‘B’ 表示黑色像素,‘W’ 表示白色像素。另给你一个整数 target ,请你找出并返回符合规则的 黑色 孤独像素的数量。
黑色孤独像素是指位于某一特定位置 (r, c) 的字符 ‘B’ ,其中:
行 r 和列 c 中的黑色像素恰好有 target 个。
列 c 中所有黑色像素所在的行必须和行 r 完全相同。
链接:https://leetcode.cn/problems/lonely-pixel-ii
class Solution:
def findBlackPixel(self, picture: List[List[str]], target: int) -> int:
m, n = len(picture), len(picture[0])
dic_r = defaultdict(list)
dic_c = defaultdict(list)
for i in range(m):
for j in range(n):
if picture[i][j] == 'B':
dic_r[i].append(j)
dic_c[j].append(i)
res = 0
# print(dic_r, dic_c)
for i in range(m):
if len(dic_r[i])!=target:
continue
for j in range(n):
if len(dic_c[j])!=target:
continue
if picture[i][j]== 'B':
y = dic_r[i]
flag = True
for x in dic_c[j]:
if dic_r[x] != y:
flag = False
break
if flag: res+=1
return res
你将获得多条日志,每条日志都有唯一的 id 和 timestamp ,timestamp 是形如 Year:Month:Day:Hour:Minute:Second 的字符串,2017:01:01:23:59:59 ,所有值域都是零填充的十进制数。
实现 LogSystem 类:
LogSystem() 初始化 LogSystem 对象
void put(int id, string timestamp) 给定日志的 id 和 timestamp ,将这个日志存入你的存储系统中。
int[] retrieve(string start, string end, string granularity) 返回在给定时间区间 [start, end] (包含两端)内的所有日志的 id 。start 、end 和 timestamp 的格式相同,granularity 表示考虑的时间粒度(例如,精确到 Day、Minute 等)。例如 start = "2017:01:01:23:59:59"、end = "2017:01:02:23:59:59" 且 granularity = "Day" 意味着需要查找从 Jan. 1st 2017 到 Jan. 2nd 2017 范围内的日志,可以忽略日志的 Hour、Minute 和 Second 。
链接:https://leetcode.cn/problems/design-log-storage-system
class LogSystem:
def __init__(self):
self.dict = defaultdict(str)
self.granularity_dict = {"Year": 4, "Month": 7, "Day": 10,
"Hour": 13, "Minute": 16, "Second": 19}
def put(self, id: int, timestamp: str) -> None:
self.dict[id] = timestamp
def retrieve(self, start: str, end: str, granularity: str) -> List[int]:
check_len = self.granularity_dict[granularity]
res = []
for key, val in self.dict.items():
if val[:check_len] >= start[:check_len] and val[:check_len] <= end[:check_len]:
res.append(key)
return res
二叉树的 边界 是由 根节点 、左边界 、按从左到右顺序的 叶节点 和 逆序的右边界 ,按顺序依次连接组成。
左边界 是满足下述定义的节点集合:
根节点的左子节点在左边界中。如果根节点不含左子节点,那么左边界就为 空 。
如果一个节点在左边界中,并且该节点有左子节点,那么它的左子节点也在左边界中。
如果一个节点在左边界中,并且该节点 不含 左子节点,那么它的右子节点就在左边界中。
最左侧的叶节点 不在 左边界中。
右边界 定义方式与 左边界 相同,只是将左替换成右。即,右边界是根节点右子树的右侧部分;叶节点 不是 右边界的组成部分;如果根节点不含右子节点,那么右边界为 空 。
叶节点 是没有任何子节点的节点。对于此问题,根节点 不是 叶节点。
给你一棵二叉树的根节点 root ,按顺序返回组成二叉树 边界 的这些值。
链接:https://leetcode.cn/problems/boundary-of-binary-tree
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def boundaryOfBinaryTree(self, root: Optional[TreeNode]) -> List[int]:
if root and not root.left and not root.right:return [root.val]
left = []
bottom = []
right = []
def leftdfs(root):
if root and (root.left or root.right):
left.append(root.val)
if root.left:
leftdfs(root.left)
else:
leftdfs(root.right)
def bottomdfs(root):
if not root: return
if not root.left and not root.right:
bottom.append(root.val)
return
bottomdfs(root.left)
bottomdfs(root.right)
def rightdfs(root):
if root and (root.left or root.right):
right.append(root.val)
if root.right:
rightdfs(root.right)
else:
rightdfs(root.left)
leftdfs(root.left)
bottomdfs(root)
rightdfs(root.right)
return [root.val] + left + bottom + right[::-1]
给你一个字符串 s 和一个字符串列表 words ,你需要将在字符串列表中出现过的 s 的子串添加加粗闭合标签 和 。
如果两个子串有重叠部分,你需要把它们一起用一对闭合标签包围起来。同理,如果两个子字符串连续被加粗,那么你也需要把它们合起来用一对加粗标签包围。
返回添加加粗标签后的字符串 s 。
链接:https://leetcode.cn/problems/add-bold-tag-in-string
class Solution:
def addBoldTag(self, s: str, words: List[str]) -> str:
n = len(s)
mask = [False for _ in range(n)]
for i in range(n):
for word in words:
if i+len(word)<=n and s[i:i+len(word)]==word:
for j in range(i, i+len(word)):
mask[j] = True
res = ''
for i in range(n):
if mask[i] and (i==0 or mask[i-1]==False):
res+=''
res+=s[i]
if mask[i] and (i==n-1 or mask[i+1]==False):
res+=''
return res
给定 m 个数组,每个数组都已经按照升序排好序了。现在你需要从两个不同的数组中选择两个整数(每个数组选一个)并且计算它们的距离。两个整数 a 和 b 之间的距离定义为它们差的绝对值 |a-b| 。你的任务就是去找到最大距离
链接:https://leetcode.cn/problems/maximum-distance-in-arrays
class Solution:
def maxDistance(self, arrays: List[List[int]]) -> int:
m = len(arrays)
res = -float('inf')
arr = []
for i in range(m):
if len(arrays[i]) == 1 or arrays[i][0]==arrays[i][-1]:
arr.append((arrays[i][0], i))
else:
minn, maxn = arrays[i][0], arrays[i][-1]
arr.append((minn, i))
arr.append((maxn, i))
arr.sort(key = lambda x:x[0])
print(arr)
if arr[0][1] == arr[-1][1]:
res = max(abs(arr[-1][0]-arr[1][0]), abs(arr[-2][0]-arr[0][0]))
else:
res = arr[-1][0]-arr[0][0]
return res
这个问题是实现一个简单的消除算法。
给定一个 m x n 的二维整数数组 board 代表糖果所在的方格,不同的正整数 board[i][j] 代表不同种类的糖果,如果 board[i][j] == 0 代表 (i, j) 这个位置是空的。
给定的方格是玩家移动后的游戏状态,现在需要你根据以下规则粉碎糖果,使得整个方格处于稳定状态并最终输出:
如果有三个及以上水平或者垂直相连的同种糖果,同一时间将它们粉碎,即将这些位置变成空的。
在同时粉碎掉这些糖果之后,如果有一个空的位置上方还有糖果,那么上方的糖果就会下落直到碰到下方的糖果或者底部,这些糖果都是同时下落,也不会有新的糖果从顶部出现并落下来。
通过前两步的操作,可能又会出现可以粉碎的糖果,请继续重复前面的操作。
当不存在可以粉碎的糖果,也就是状态稳定之后,请输出最终的状态。
你需要模拟上述规则并使整个方格达到稳定状态,并输出。
链接:https://leetcode.cn/problems/candy-crush
class Solution:
def candyCrush(self, board: List[List[int]]) -> List[List[int]]:
m, n = len(board), len(board[0])
mask = [[False for _ in range(n)]for _ in range(m)]
while 1:
mask = [[False for _ in range(n)]for _ in range(m)]
flag = False
for i in range(m):
for j in range(n-2):
if board[i][j]!=0 and board[i][j] == board[i][j+1] == board[i][j+2]:
flag = True
mask[i][j] = mask[i][j+1] = mask[i][j+2] = True
for i in range(n):
for j in range(m-2):
if board[j][i]!=0 and board[j][i] == board[j+1][i] == board[j+2][i]:
flag = True
mask[j][i] = mask[j+1][i] = mask[j+2][i] = True
if flag:
for c in range(n):
rr = m - 1
for r in range(m - 1, -1, -1):
if mask[r][c] == False:
board[rr][c] = board[r][c]
rr -= 1
while rr > -1:
board[rr][c] = 0
rr -= 1
else:
break
return board
并查集
我们可以将一个句子表示为一个单词数组,例如,句子 I am happy with leetcode"可以表示为 arr = [“I”,“am”,happy",“with”,“leetcode”]
给定两个句子 sentence1 和 sentence2 分别表示为一个字符串数组,并给定一个字符串对 similarPairs ,其中 similarPairs[i] = [xi, yi] 表示两个单词 xi 和 yi 是相似的。
如果 sentence1 和 sentence2 相似则返回 true ,如果不相似则返回 false 。
两个句子是相似的,如果:
请注意,一个词总是与它自己相似,也请注意,相似关系是可传递的。例如,如果单词 a 和 b 是相似的,单词 b 和 c 也是相似的,那么 a 和 c 也是 相似 的。
链接:https://leetcode.cn/problems/sentence-similarity-ii
class Union:
def __init__(self, n):
self.father = [i for i in range(n)]
def findFather(self, x):
while x != self.father[x]:
self.father[x] = self.father[self.father[x]]
x = self.father[x]
return x
def union(self, x, y):
fa_x = self.findFather(x)
fa_y = self.findFather(y)
if fa_x != fa_y:
if fa_x < fa_y:
fa_x, fa_y = fa_y, fa_x
self.father[fa_y] = fa_x
def isConnect(self, x, y):
fa_x = self.findFather(x)
fa_y = self.findFather(y)
return fa_x==fa_y
class Solution:
def areSentencesSimilarTwo(self, sentence1: List[str], sentence2: List[str], similarPairs: List[List[str]]) -> bool:
if len(sentence1) != len(sentence2): return False
n = len(sentence1)
sentence = sentence1 + sentence2
dic = dict()
Id = 0
for x in sentence:
if x not in dic:
dic[x] = Id
Id += 1
for x,y in similarPairs:
if x not in dic:
dic[x] = Id
Id += 1
if y not in dic:
dic[y] = Id
Id += 1
uf = Union(Id)
for x,y in similarPairs:
uf.union(dic[x], dic[y])
for i in range(n):
if not uf.isConnect(dic[sentence1[i]], dic[sentence2[i]]):
return False
return True
假设你有一个特殊的键盘包含下面的按键:
A:在屏幕上打印一个 'A'。
Ctrl-A:选中整个屏幕。
Ctrl-C:复制选中区域到缓冲区。
Ctrl-V:将缓冲区内容输出到上次输入的结束位置,并显示在屏幕上。
现在,你可以 最多 按键 n 次(使用上述四种按键),返回屏幕上最多可以显示 'A' 的个数 。
链接:https://leetcode.cn/problems/4-keys-keyboard
class Solution:
def maxA(self, n: int) -> int:
#### dfs
# self.res = 0
# def dfs(cur_i, nums, tmp):
# if cur_i == n:
# self.res = max(self.res, nums)
# return
# pathway = [1,3,1]
# for i in range(3):
# di = pathway[i]
# if 0 <= cur_i+di <= n:
# ni = cur_i + di
# if i == 0:
# dfs(ni, nums+1, tmp)
# elif i==1:
# dfs(ni, nums*2, nums)
# elif i==2:
# dfs(ni, nums+tmp, tmp)
# dfs(0,0,0)
# return self.res
#### dp
self.res = 0
f = [0 for _ in range(n)]
f[0] = 1
for i in range(1, n):
f[i] = f[i-1] + 1
for j in range(i):
f[i] = max(f[i], f[j]*(i-j-2+1))
return (f[n-1])
给定一棵有 n 个结点的二叉树,你的任务是检查是否可以通过去掉树上的一条边将树分成两棵,且这两棵树结点之和相等。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def checkEqualTree(self, root: Optional[TreeNode]) -> bool:
def sumTree(root):
if not root:
return 0
left = sumTree(root.left)
right = sumTree(root.right)
return root.val + left + right
summ = sumTree(root)
if summ % 2 != 0:
return False
target = summ//2
def findtarget(root, pre):
if not root:
return False
if pre and sumTree(root) == target:
return True
return findtarget(root.left, root) or findtarget(root.right, root)
return findtarget(root, None)
对于一棵深度小于 5 的树,可以用一组三位十进制整数来表示。对于每个整数:
百位上的数字表示这个节点的深度 d,1 <= d <= 4。
十位上的数字表示这个节点在当前层所在的位置 P, 1 <= p <= 8。位置编号与一棵满二叉树的位置编号相同。
个位上的数字表示这个节点的权值 v,0 <= v <= 9。
给定一个包含三位整数的 升序 数组 nums ,表示一棵深度小于 5 的二叉树,请你返回 从根到所有叶子结点的路径之和 。
保证 给定的数组表示一个有效的连接二叉树。
链接:https://leetcode.cn/problems/path-sum-iv
class Solution:
def pathSum(self, nums: List[int]) -> int:
def int2arr(x):
arr = [int(str(x)[0]),int(str(x)[1]) ,int(str(x)[2])]
return arr
arr = []
for x in nums:
tmp = int2arr(x)
arr.append(tmp)
root = arr[0]
st = [root]
res = []
while st:
tmp = st
st = []
while tmp:
depth, width, summ = tmp.pop(0)
flag1, flag2=False, False
for d, w, n in arr:
if d==depth+1 and w == width*2-1:
st.append([d, w, summ+n])
flag1=True
for d, w, n in arr:
if d==depth+1 and w == width*2:
st.append([d, w, summ+n])
flag1=True
if not flag1 and not flag2:
res.append(summ)
return (sum(res))
给你一棵二叉树的根节点 root,找出这棵树的 每一棵 子树的 平均值 中的 最大 值。
子树是树中的任意节点和它的所有后代构成的集合。
树的平均值是树中节点值的总和除以节点数。
链接:https://leetcode.cn/problems/maximum-average-subtree
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maximumAverageSubtree(self, root: Optional[TreeNode]) -> float:
def sumTree(root, nums):
if not root:
return 0, 0
left, nums_l = sumTree(root.left, nums+1)
right, nums_r = sumTree(root.right, nums+1)
return root.val + left + right, nums_l+nums_r+1
self.res = 0
def dfs(root):
if not root:
return
dfs(root.left)
dfs(root.right)
summ, nums = sumTree(root, 0)
self.res = max(self.res, summ/nums)
dfs(root)
return self.res
给定两个字符串数组 username 和 website 和一个整数数组 timestamp 。给定的数组长度相同,其中元组 [username[i], website[i], timestamp[i]] 表示用户 username[i] 在时间 timestamp[i] 访问了网站 website[i] 。
访问模式 是包含三个网站的列表(不一定是完全不同的)。
例如,[“home”, “away”, “love”], [“leetcode”, “love”, “leetcode”],和 [“luffy”, “luffy”, “luffy”] 都是模式。
一种 访问模式 的 得分 是访问该模式中所有网站的用户数量,这些网站在该模式中出现的顺序相同。
例如,如果模式是 [“home”,“away”,“love”] ,那么分数就是用户数量 x , x 访问了 “home” ,然后访问了 “away” ,然后访问了 “love” 。
同样,如果模式是 [“leetcode”, “love”, “leetcode”] ,那么分数就是用户数量 x ,使得 x 访问了"leetcode",然后访问了 “love” ,之后又访问了 “leetcode” 。
另外,如果模式是 [“luffy”,“luffy”,“luffy”] ,那么分数就是用户数量 x ,这样 x 就可以在不同的时间戳上访问 “luffy” 三次。
返回 得分 最大的 访问模式 。如果有多个访问模式具有相同的最大分数,则返回字典序最小的。
链接:https://leetcode.cn/problems/analyze-user-website-visit-pattern
class Solution:
def mostVisitedPattern(self, username: List[str], timestamp: List[int], website: List[str]) -> List[str]:
dict_input = dict(zip(timestamp, zip(username, website)))
dict_user = defaultdict(list)
from sortedcontainers import SortedDict as SD
mode = SD()
print(sorted(dict_input.keys()))
# for i in range(len(username)):
for key in sorted(dict_input.keys()):
user, web = dict_input[key]
dict_user[user].append(web)
for k,v in dict_user.items():
if len(v)>=3:
tmp_path_set = set()
for i in range(len(v)-2):
for j in range(i+1, len(v)-1):
for z in range(j+1, len(v)):
tmp_path_set.add(tuple([v[i],v[j],v[z]]))
for p in tmp_path_set:
if p not in mode:
mode[p] = 0
mode[p] += 1
print(dict_user, mode)
maxm = 0
self.res = []
for k,v in mode.items():
if v>maxm:
maxm = v
self.res = list(k)
return (self.res)
你需要设计一个文件系统,你可以创建新的路径并将它们与不同的值关联。
路径的格式是一个或多个连接在一起的字符串,形式为: / ,后面跟着一个或多个小写英文字母。例如, " /leetcode" 和 “/leetcode/problems” 是有效路径,而空字符串 “” 和 “/” 不是。
实现 FileSystem 类:
bool createPath(string path, int value) 创建一个新的 path ,并在可能的情况下关联一个 value ,然后返回 true 。如果路径已经存在或其父路径不存在,则返回 false 。
int get(string path) 返回与 path 关联的值,如果路径不存在则返回 -1 。
链接:https://leetcode.cn/problems/design-file-system
class FileSystem:
def __init__(self):
self.path_dict = defaultdict(int)
def createPath(self, path: str, value: int) -> bool:
if path == '' or path == '/':
return False
arr = path.split('/')[1:]
if '/' in arr:
return False
if tuple(arr) in self.path_dict:
return False
elif len(arr)>1:
if tuple(arr[:len(arr)-1]) not in self.path_dict:
return False
self.path_dict[tuple(arr)] = value
return True
def get(self, path: str) -> int:
arr = path.split('/')[1:]
if tuple(arr) not in self.path_dict:
return -1
else:
return self.path_dict[tuple(arr)]
# Your FileSystem object will be instantiated and called as such:
# obj = FileSystem()
# param_1 = obj.createPath(path,value)
# param_2 = obj.get(path)
你有一些长度为正整数的棍子。这些长度以数组 sticks 的形式给出, sticks[i] 是 第i个 木棍的长度。
你可以通过支付 x + y 的成本将任意两个长度为 x 和 y 的棍子连接成一个棍子。你必须连接所有的棍子,直到剩下一个棍子。
返回以这种方式将所有给定的棍子连接成一个棍子的 最小成本 。
链接:https://leetcode.cn/problems/minimum-cost-to-connect-sticks
用heapq排序,每次取最小的两个,用sort会超时
class Solution:
def connectSticks(self, sticks: List[int]) -> int:
ans = 0
heap = []
for n in sticks:
heapq.heappush(heap, n)
while len(heap) >= 2:
a = heapq.heappop(heap)
b = heapq.heappop(heap)
c = a + b
ans += c
heapq.heappush(heap, c)
return ans
利用set的特点
class Solution:
def smallestCommonElement(self, mat: List[List[int]]) -> int:
a = set(mat[0])
for i in range(len(mat)):
a = a & set(mat[i])
print(a)
a = list(a)
if len(a) == 0:
return -1
return a[0]
给出两棵二叉搜索树的根节点 root1 和 root2 ,请你从两棵树中各找出一个节点,使得这两个节点的值之和等于目标值 Target。
如果可以找到返回 True,否则返回 False。
链接:https://leetcode.cn/problems/two-sum-bsts
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def twoSumBSTs(self, root1: Optional[TreeNode], root2: Optional[TreeNode], target: int) -> bool:
self.res = []
def dfs(root):
if not root: return
dfs(root.left)
self.res.append(root.val)
dfs(root.right)
dfs(root1)
res1 = self.res.copy()
self.res = []
dfs(root2)
res2 = self.res.copy()
for x in res1:
if target - x in res2:
return True
return False
新一轮的「力扣杯」编程大赛即将启动,为了动态显示参赛者的得分数据,需要设计一个排行榜 Leaderboard。
请你帮忙来设计这个 Leaderboard 类,使得它有如下 3 个函数:
addScore(playerId, score):
假如参赛者已经在排行榜上,就给他的当前得分增加 score 点分值并更新排行。
假如该参赛者不在排行榜上,就把他添加到榜单上,并且将分数设置为 score。
top(K):返回前 K 名参赛者的 得分总和。
reset(playerId):将指定参赛者的成绩清零(换句话说,将其从排行榜中删除)。题目保证在调用此函数前,该参赛者已有成绩,并且在榜单上。
请注意,在初始状态下,排行榜是空的。
链接:https://leetcode.cn/problems/design-a-leaderboard
class Leaderboard:
def __init__(self):
self.board = dict()
def addScore(self, playerId: int, score: int) -> None:
if playerId not in self.board:
self.board[playerId] = score
else:
self.board[playerId] += score
def top(self, K: int) -> int:
a = sorted(self.board.items(), key=lambda x:x[1], reverse=True)
ans = 0
a = a[:K]
for k, v in a:
ans += v
return ans
def reset(self, playerId: int) -> None:
if playerId in self.board:
del self.board[playerId]
# Your Leaderboard object will be instantiated and called as such:
# obj = Leaderboard()
# obj.addScore(playerId,score)
# param_2 = obj.top(K)
# obj.reset(playerId)
给您一个不可变的链表,使用下列接口逆序打印每个节点的值:
ImmutableListNode: 描述不可变链表的接口,链表的头节点已给出。
您需要使用以下函数来访问此链表(您 不能 直接访问 ImmutableListNode):
ImmutableListNode.printValue():打印当前节点的值。
ImmutableListNode.getNext():返回下一个节点。
输入只用来内部初始化链表。您不可以通过修改链表解决问题。也就是说,您只能通过上述 API 来操作链表。
链接:https://leetcode.cn/problems/print-immutable-linked-list-in-reverse
# """
# This is the ImmutableListNode's API interface.
# You should not implement it, or speculate about its implementation.
# """
# class ImmutableListNode:
# def printValue(self) -> None: # print the value of this node.
# def getNext(self) -> 'ImmutableListNode': # return the next node.
class Solution:
def printLinkedListInReverse(self, head: 'ImmutableListNode') -> None:
def dfs(node):
if node == None: return
dfs(node.getNext())
node.printValue()
dfs(head)
如果一个整数上的每一位数字与其相邻位上的数字的绝对差都是 1,那么这个数就是一个「步进数」。
例如,321 是一个步进数,而 421 不是。
给你两个整数,low 和 high,请你找出在 [low, high] 范围内的所有步进数,并返回 排序后 的结果。
链接:https://leetcode.cn/problems/stepping-numbers
BFS
class Solution:
def countSteppingNumbers(self, low: int, high: int) -> List[int]:
res = []
if low == 0:
res.append(low)
queue = [x for x in range(1,10)]
while queue:
tmp = queue.pop(0)
if tmp > high:
return res
if tmp >= low:
res.append(tmp)
last = tmp % 10
if last > 0:
queue.append(tmp*10 + last - 1)
if last < 9:
queue.append(tmp*10 + last + 1)
return res
给你一个非负整数 num ,返回它的「加密字符串」。
加密的过程是把一个整数用某个未知函数进行转化,你需要从下表推测出该转化函数:
class Solution:
def encode(self, num: int) -> str:
new_num = bin(num+1)
print(new_num)
length = len(str(new_num))
return str(new_num)[3: length]
给你一个数组 colors,里面有 1、2、 3 三种颜色。
我们需要在 colors 上进行一些查询操作 queries,其中每个待查项都由两个整数 i 和 c 组成。
现在请你帮忙设计一个算法,查找从索引 i 到具有目标颜色 c 的元素之间的最短距离。
如果不存在解决方案,请返回 -1。
链接:https://leetcode.cn/problems/shortest-distance-to-target-color
class Solution:
def shortestDistanceColor(self, colors: List[int], queries: List[List[int]]) -> List[int]:
ans = []
dic_color = defaultdict(list)
for idx,x in enumerate(colors):
dic_color[x].append(idx)
for x,y in queries:
if y not in dic_color:
ans.append(-1)
else:
if colors[x] == y:
ans.append(0)
else:
arr = dic_color[y]
left, right = 0, len(arr)-1
if x<=arr[left]:
ans.append(abs(arr[left]-x))
elif x>=arr[right]:
ans.append(abs(arr[right]-x))
else:
while left <= right:
mid = (left+right)//2
if x > arr[mid]: left = mid+1
else: right = mid-1
ans.append(min(abs(arr[left] - x), abs(arr[left - 1] - x)))
return ans
有一些不规则的硬币。在这些硬币中,prob[i] 表示第 i 枚硬币正面朝上的概率。
请对每一枚硬币抛掷 一次,然后返回正面朝上的硬币数等于 target 的概率。
链接:https://leetcode.cn/problems/toss-strange-coins
class Solution:
def probabilityOfHeads(self, prob: List[float], target: int) -> float:
m = len(prob)
dp = [[0 for _ in range(target+1)] for _ in range(m+1)]
dp[0][0] = 1
for i in range(m):
dp[i+1][0] = dp[i][0]*(1-prob[i])
for i in range(1,m+1):
for j in range(1,target+1):
dp[i][j] = dp[i-1][j]*(1-prob[i-1])+dp[i-1][j-1]*prob[i-1]
return dp[-1][-1]
给你一个近义词表 synonyms 和一个句子 text , synonyms 表中是一些近义词对 ,你可以将句子 text 中每个单词用它的近义词来替换。
请你找出所有用近义词替换后的句子,按 字典序排序 后返回。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/synonymous-sentences
PS:利用并查集,确定近义词集合
class Union:
def __init__(self, n):
self.father = [x for x in range(n)]
def findFather(self, x):
while x!=self.father[x]:
self.father[x] = self.father[self.father[x]]
x = self.father[x]
return x
def union(self,x,y):
root1 = self.findFather(x)
root2 = self.findFather(y)
if root1 != root2:
if root2 > root1:
self.father[root2] = root1
else:
self.father[root1] = root2
def isConnect(self,x,y):
return self.findFather(x)==self.findFather(y)
class Solution:
def generateSentences(self, synonyms: List[List[str]], text: str) -> List[str]:
arr_str = text.split(' ')
word_id_dict = defaultdict(int)
idx = 0
for x,y in synonyms:
if x not in word_id_dict:
word_id_dict[x] = idx
idx+=1
if y not in word_id_dict:
word_id_dict[y] = idx
idx+=1
uf = Union(idx)
for x, y in synonyms:
uf.union(word_id_dict[x], word_id_dict[y])
syn_dict = defaultdict(set)
for x in word_id_dict.keys():
for y in word_id_dict.keys():
if x==y:
continue
if uf.isConnect(word_id_dict[x], word_id_dict[y]):
syn_dict[x].add(y)
self.res = set()
self.res.add(text)
def dfs(arr, i):
if i == len(arr):
return
for j in range(i,len(arr)):
print(arr[j])
if arr[j] in syn_dict:
for v in syn_dict[arr[j]]:
tmp = arr.copy()
tmp[j] = v
self.res.add(' '.join(tmp))
dfs(tmp, j+1)
tmp = arr.copy()
self.res.add(' '.join(tmp))
dfs(tmp, j+1)
dfs(arr_str,0)
self.res = list(self.res)
self.res.sort()
return self.res
给定一个链接 startUrl 和一个接口 HtmlParser ,请你实现一个网络爬虫,以实现爬取同 startUrl 拥有相同 域名标签 的全部链接。该爬虫得到的全部链接可以 任何顺序 返回结果。
链接:https://leetcode.cn/problems/web-crawler
# """
# This is HtmlParser's API interface.
# You should not implement it, or speculate about its implementation
# """
#class HtmlParser(object):
# def getUrls(self, url):
# """
# :type url: str
# :rtype List[str]
# """
class Solution:
def crawl(self, startUrl: str, htmlParser: 'HtmlParser') -> List[str]:
start_strr=startUrl[7:]
start_name = 'http://'+start_strr.split('/')[0]
res = set()
res.add(startUrl)
st = [startUrl]
while st:
tmp_str = st.pop(0)
res.add(tmp_str)
for x in htmlParser.getUrls(tmp_str):
if x not in res and x.startswith(start_name):
st.append(x)
return (res)
给你一些区域列表 regions ,每个列表的第一个区域都包含这个列表内所有其他区域。
很自然地,如果区域 X 包含区域 Y ,那么区域 X 比区域 Y 大。
给定两个区域 region1 和 region2 ,找到同时包含这两个区域的 最小 区域。
如果区域列表中 r1 包含 r2 和 r3 ,那么数据保证 r2 不会包含 r3 。
数据同样保证最小公共区域一定存在。
链接:https://leetcode.cn/problems/smallest-common-region
class Solution:
def findSmallestRegion(self, regions: List[List[str]], region1: str, region2: str) -> str:
fa_dict = dict()
for region in regions:
fa = region[0]
for child in region[1:]:
fa_dict[child] = fa
r1, r2 = region1, region2
r1_fas = [r1]
while r1 in fa_dict:
r1 = fa_dict[r1]
r1_fas.append(r1)
while r2 in fa_dict:
if r2 in r1_fas:
return r2
r2 = fa_dict[r2]
return r2
实数集合可以表示为若干不相交区间的并集,其中每个区间的形式为 [a, b)(左闭右开),表示满足 a <= x < b 的所有实数 x 的集合。如果某个区间 [a, b) 中包含实数 x ,则称实数 x 在集合中。
给你一个 有序的 不相交区间列表 intervals 。intervals 表示一个实数集合,其中每一项 intervals[i] = [ai, bi] 都表示一个区间 [ai, bi) 。再给你一个要删除的区间 toBeRemoved 。
返回 一组实数,该实数表示intervals 中 删除 了 toBeRemoved 的部分 。换句话说,返回实数集合,并满足集合中的每个实数 x 都在 intervals 中,但不在 toBeRemoved 中。你的答案应该是一个如上所述的 有序的 不相连的间隔列表 。
链接:https://leetcode.cn/problems/remove-interval
class Solution:
def removeInterval(self, intervals: List[List[int]], toBeRemoved: List[int]) -> List[List[int]]:
res = []
for x,y in intervals:
tmp_x = min(x, toBeRemoved[0])
tmp_y = max(y, toBeRemoved[1])
if tmp_x == x and tmp_y == y:
if tmp_x == x == toBeRemoved[0] and tmp_y == y == toBeRemoved[1]:
continue
elif tmp_x == x == toBeRemoved[0]:
res.append([toBeRemoved[1], y])
elif tmp_y == y == toBeRemoved[1]:
res.append([x, toBeRemoved[0]])
else:
res.append([x,toBeRemoved[0]])
res.append([toBeRemoved[1],y])
elif tmp_x == x and tmp_y == toBeRemoved[1]:
res.append([x, min(y,toBeRemoved[0])])
elif tmp_x == toBeRemoved[0] and tmp_y == y:
res.append([max(x,toBeRemoved[1]), y])
return res
class Solution:
def deleteTreeNodes(self, nodes: int, parent: List[int], value: List[int]) -> int:
edges = [[] for _ in range(nodes)]
for x, p in enumerate(parent):
if p != -1:
edges[p].append(x)
cnt_node = [1 for _ in range(nodes)]
def dfs(node):
for v in edges[node]:
dfs(v)
value[node] += value[v]
cnt_node[node] += cnt_node[v]
if value[node] == 0:
cnt_node[node] = 0
dfs(0)
return cnt_node[0]
class Solution:
def boldWords(self, words: List[str], s: str) -> str:
n = len(s)
mask = [False for _ in range(n)]
for i in range(n):
for word in words:
if i+len(word)<=n and s[i:i+len(word)]==word:
for j in range(len(word)):
mask[i+j] = True
res = ''
for idx, x in enumerate(mask):
if mask[idx] and (idx==0 or mask[idx-1]==False):
res+=''
res+=s[idx]
if mask[idx] and (idx==n-1 or mask[idx+1]==False):
res+=''
return res
二分查找 binary-search
class Solution:
def boldWords(self, words: List[str], s: str) -> str:
n = len(s)
mask = [False for _ in range(n)]
for i in range(n):
for word in words:
if i+len(word)<=n and s[i:i+len(word)]==word:
for j in range(len(word)):
mask[i+j] = True
res = ''
for idx, x in enumerate(mask):
if mask[idx] and (idx==0 or mask[idx-1]==False):
res+=''
res+=s[idx]
if mask[idx] and (idx==n-1 or mask[idx+1]==False):
res+=''
return res
class Solution:
def minTime(self, time: List[int], m: int) -> int:
left, right = 0, sum(time)
while left<right:
L = (left+right)//2
if self.isTime(L, time, m):
right = L
else:
left = L+1
return left
def isTime(self, Limit, time, m):
cur_time = 0
max_time = time[0]
days = 1
for x in time[1:]:
if cur_time + min(max_time, x)<=Limit:
cur_time += min(max_time,x)
max_time = max(max_time, x)
else:
cur_time = 0
days += 1
# max_time = min(max_time, x)
max_time = x
if days>m:
return False
else:
return True
给定一个正整数 a,找出最小的正整数 b 使得 b 的所有数位相乘恰好等于 a。
如果不存在这样的结果或者结果不是 32 位有符号整数,返回 0。
class Solution:
def smallestFactorization(self, num: int) -> int:
res = 0
weight = 1
if num<=9:
return num
for x in range(9,1,-1):
while num%x == 0:
num //= x
res = weight*x + res
weight *= 10
if res >= 2**31-1:
return 0
if num!=1:
return 0
return res
动态规划
给定一个只包含 0 和 1 的 m x n 整数矩阵 grid ,返回 其中 「角矩形 」的数量 。
一个「角矩形」是由四个不同的在矩阵上的 1 形成的 轴对齐 的矩形。注意只有角的位置才需要为 1。
注意:4 个 1 的位置需要是不同的。
链接:https://leetcode.cn/problems/number-of-corner-rectangles
class Solution:
def countCornerRectangles(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
dp = [[0 for _ in range(n)] for _ in range(n)]
res = 0
for i in range(m):
for j in range(n):
if grid[i][j]==1:
for k in range(j+1,n):
if grid[i][k]==1:
res+=dp[j][k]
dp[j][k]+=1
return res
并查集的应用
给你一个大小为 m x n 的二进制网格 grid 。网格表示一个地图,其中,0 表示水,1 表示陆地。最初,grid 中的所有单元格都是水单元格(即,所有单元格都是 0)。
可以通过执行 addLand 操作,将某个位置的水转换成陆地。给你一个数组 positions ,其中 positions[i] = [ri, ci] 是要执行第 i 次操作的位置 (ri, ci) 。
返回一个整数数组 answer ,其中 answer[i] 是将单元格 (ri, ci) 转换为陆地后,地图中岛屿的数量。
岛屿 的定义是被「水」包围的「陆地」,通过水平方向或者垂直方向上相邻的陆地连接而成。你可以假设地图网格的四边均被无边无际的「水」所包围。
链接:https://leetcode.cn/problems/number-of-islands-ii
class FindUnion:
def __init__(self,n):
self.father = [x for x in range(n)]
self.cluster = 0
self.size = [1 for _ in range(n)]
def findFather(self,x):
while x!=self.father[x]:
self.father[x] = self.father[self.father[x]]
x = self.father[x]
return x
def Union(self,x,y):
root_x = self.findFather(x)
root_y = self.findFather(y)
if root_x == root_y:
return True
else:
if root_x > root_y:
self.father[root_x] = root_y
self.size[root_x] += self.size[root_y]
else:
self.father[root_y] = root_x
self.size[root_y] += self.size[root_x]
self.cluster -= 1
return True
class Solution:
def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]:
uf = FindUnion(m*n)
seen = set()
res = []
for x,y in positions:
ID = x*n+y
if ID in seen:
res.append(uf.cluster)
continue
seen.add(ID)
uf.cluster += 1
for nr, nc in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)]:
if 0<=nr<m and 0<=nc<n:
Id2 = nr*n+nc
if Id2 in seen:
uf.Union(ID, Id2)
res.append(uf.cluster)
return res
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
链接:https://leetcode.cn/problems/binary-tree-maximum-path-sum
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
self.res = -float('inf')
def dfs(root):
if not root: return 0
left = dfs(root.left)
right = dfs(root.right)
self.res=max(self.res,root.val+left+right, root.val+left, root.val+right, root.val)
print(root.val, self.res)
return max(root.val+left, root.val+right, root.val)
dfs(root)
return self.res
动态规划
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
链接:https://leetcode.cn/problems/edit-distance
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0 for _ in range(n+1)]for _ in range(m+1)]
for i in range(m+1):
dp[i][0] = i
for i in range(n+1):
dp[0][i] = i
for i in range(1,m+1):
for j in range(1,n+1):
left = dp[i][j-1] + 1
right = dp[i-1][j] + 1
lr = dp[i-1][j-1]
if word1[i-1]!=word2[j-1]:
lr += 1
dp[i][j] = min(left, right, lr)
return dp[m][n]
快排
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def getIndex(nums, left, right):
p = nums[left]
while left < right:
while left < right and p<=nums[right]:
right -= 1
nums[left] = nums[right]
while left < right and p>=nums[left]:
left += 1
nums[right] = nums[left]
nums[left] = p
return left
def randomIndex(nums, left, right):
index = random.randint(left, right)
nums[left], nums[index] = nums[index],nums[left]
return getIndex(nums,left,right)
def quickSort(nums, left, right):
if left<right:
mid = randomIndex(nums,left,right)
quickSort(nums, left, mid-1)
quickSort(nums, mid+1, right)
quickSort(nums,0,len(nums)-1)
return nums