学习来源:
1518
1、模拟:
先把所有的酒喝完,得到n个空酒瓶。随后,每次可以拿e
个空酒瓶换1
瓶新酒,将这1
瓶新酒喝完,与剩下的e-1
个酒瓶,去换新酒……
res = numBottles
emptyBottles = numBottles
while emptyBottles >= ExchangeBottles:
# 换酒
emptyBottles -= ExchangeBottles
# 喝完新酒
emptyBottles += 1
# 多喝了一瓶
res += 1
return res
2、数学方法:
方法1中可以看出,每次换酒后,空瓶子会减少e-1
个,直到剩余空酒瓶无法换取新酒。假设当前一共换了n瓶,则有:emptyBottles = emptyBottles - n*(e-1)
。因此,只需求解使得emptyBottles - n*(e-1) < ExchangeBottles
成立的最小n。
if numBottles < ExchangeBottles:
return numBottles
else:
numBottles += (numBottles-ExchangeBottles)//(ExchangeBottles-1)+1
return numBottles
1519
算法思想:DFS
tips:
当题目只说给出一棵树,或者说连通的无环无向图时,需要考虑边的含义,l = [a,b]
不表示a
是b
的父节点,只能说明二者存在连线。
DFS传递父节点方法:
edge_list = collections.defaultdict(list)
# 存储节点间关系
for i,j in edges:
edge_list[i].append(j)
edge_list[j].append(i)
def dfs(cur_node,pre_node):
# 统计当前节点的label
count_list[cur_node][ord(labels[cur_node])-ord('a')] = 1
# 深度搜索当前节点下所有相连节点的label
for next_node in edge_list[cur_node]:
# 排除父节点
if next_node != pre_node:
dfs(next_node,cur_node)
for i in range(26):
count_list[cur_node][i] += count_list[next_node][i]
count_list = [[0]*26 for _ in range(n)]
dfs(0,-1)
res = []
for i in range(n):
res.append(count_list[i][ord(labels[i])-ord('a')])
return res
DFS访问列表标记
edge_list = collections.defaultdict(list)
# 存储节点间关系
for i,j in edges:
edge_list[i].append(j)
edge_list[j].append(i)
# 传递访问标记列表
def dfs(cur_node,visit):
visit[cur_node] = 1
count_list[cur_node][ord(labels[cur_node])-ord('a')] = 1
for next_node in edge_list[cur_node]:
if visit[next_node] == 0:
dfs(next_node,visit)
for i in range(26):
count_list[cur_node][i] += count_list[next_node][i]
count_list = [[0]*26 for _ in range(n)]
visit = [0 for _ in range(n)]
dfs(0,visit)
res = []
for i in range(n):
res.append(count_list[i][ord(labels[i])-ord('a')])
return res
1520
算法思想:贪心
template:
有一个[0,n-1]
的线段,其中n=s.length
,要求我们用尽可能多的小线段覆盖这个线段,且线段之间不能重合,线段之和最小。
answer_tips:
将可用线段按右端点为第一关键字,长度为第二关键字进行排序。随后从前往后遍历线段,遇到可以加入的直接贪心添加。
要求2
强调若一个子字符串包含c,则s中所有的c都应该包含于该字串。
# 先创建segment类
class segment():
def __init__(self,left=-1,right=-1):
self.left = left
self.right = right
# 增加富比较
def __lt__(self,other):
if self.right == other.right:
return self.left > other.left
else:
return self.right < other.right
seg = [segment() for _ in range(26)]
# 预处理左右端点
lens = len(s)
for i in range(lens):
cur_ind = ord(i)-ord('a')
if seg[cur_ind].left == -1:
seg[cur_ind].left = seg[cur_ind].right = i
else:
seg[cur_ind].right = i
# 处理每个片段,使之满足条件2
for i in range(26):
if seg[i].left != -1:
# 处理当前片段的每个字符
j = seg[i].left
while j <= seg[i].right:
cur_ind = ord(j)-ord('a')
if seg[cur_ind].left >= seg[i].left and seg[cur_ind].right <= seg[i].right:
pass
else:
seg[i].left = min(seg[i].left,seg[cur_ind].left)
seg[i].right = max(seg[i].right,seg[cur_ind].right)
j = seg[i].left
j += 1
# 贪心算法,此时需要先根据右端点进行排序,随后按照字符串长度排序,返回类中定义排序
seg.sort()
res = []
end = -1
for i in seg:
left, right = i.left, i.right
if left == -1:
continue
# 此时已经完成排序,只需满足条件1:无重叠(严格无重叠)
elif end == -1 or left > end:
end = right
res.append(s[left:right+1])
return res