一、1486. 数组异或操作:
给你两个整数,n 和 start 。
数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。
请返回 nums 中所有元素按位异或(XOR)后得到的结果。
示例:
输入:n = 5, start = 0
输出:8
解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。
"^" 为按位异或 XOR 运算符。
分析:
简单的模拟过程。
代码(Python):
class Solution:
def xorOperation(self, n: int, start: int) -> int:
ans = 0
for i in range(n):
cur = start + 2 * i
ans = ans ^ cur
return ans
二、1487. 保证文件名唯一:
给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹。
由于两个文件 不能 共享相同的文件名,因此如果新建文件夹使用的文件名已经被占用,系统会以(k)
的形式为新文件夹的文件名添加后缀,其中 k 是能保证文件名唯一的 最小正整数 。
返回长度为 n 的字符串数组,其中 ans[i] 是创建第 i 个文件夹时系统分配给该文件夹的实际名称。
示例:
输入:names = ["pes","fifa","gta","pes(2019)"]
输出:["pes","fifa","gta","pes(2019)"]
解释:文件系统将会这样创建文件名:
"pes" --> 之前未分配,仍为 "pes"
"fifa" --> 之前未分配,仍为 "fifa"
"gta" --> 之前未分配,仍为 "gta"
"pes(2019)" --> 之前未分配,仍为 "pes(2019)"输入:names = ["kaido","kaido(1)","kaido","kaido(1)"]
输出:["kaido","kaido(1)","kaido(2)","kaido(1)(1)"]
解释:注意,如果含后缀文件名被占用,那么系统也会按规则在名称后添加新的后缀 (k) 。
分析:
当时在做的时候写了几个版本:
(1):题目理解错误。我直接把所有文件名后面的括号及括号中数字全部去掉。接着利用哈希表存储同名元素个数。但是示例二提示:含后缀文件名被占用,那么还要继续添加新后缀。
(2):TLE。理解正确,但是
# ...
name_set = defaultdict(int)
for name in names:
# 如果第一次出现该文件名
if not name_set[name]:
ans.append(name)
name_set[name] += 1
# 如果已经出现,最重要的部分!
else:
times = 0
new_name = "{name}({times})".format(name=name, times=times)
while name_set[new_name]:
times += 1
new_name = "{name}({times})".format(name=name, times=times)
ans.append(new_name)
name_set[new_name] += 1
# ...
- 当发现该文件名已经被占用,首先添加后缀,如果后缀仍然被占用,则括号中数字不断++。
- 上面就是题目的大概思路,但是问题在于没有利用Hash表中存储的数字。对上面的代码稍加修改就可以通过。
代码(Python):
class Solution:
def getFolderNames(self, names: List[str]) -> List[str]:
ans = []
name_set = defaultdict(int)
for name in names:
if not name_set[name]:
ans.append(name)
name_set[name] += 1
else:
# 非常重要,由于defaultdict(int)默认值为0,而此时直接插入已经失败,说明要添加后缀
# 如果此时的name已经带后缀,应该直接加后缀,下标应从1开始
if not name_set[name]:
name_set[name] = 1
new_name = "{name}({times})".format(name=name, times=name_set[name])
while name_set[new_name]:
name_set[name] += 1
new_name = "{name}({times})".format(name=name, times=name_set[name])
ans.append(new_name)
name_set[new_name] += 1
return ans
三、1488. 避免洪水泛滥:
你的国家有无数个湖泊,所有湖泊一开始都是空的。当第 n 个湖泊下雨的时候,如果第 n 个湖泊是空的,那么它就会装满水,否则这个湖泊会发生洪水。你的目标是避免任意一个湖泊发生洪水。
给你一个整数数组 rains ,其中:
-
rains[i] > 0
表示第 i 天时,第 rains[i] 个湖泊会下雨。 -
rains[i] == 0
表示第 i 天没有湖泊会下雨,你可以选择 一个 湖泊并 抽干 这个湖泊的水。
请返回一个数组 ans ,满足:
-
ans.length == rains.length
-
如果
rains[i] > 0
,那么ans[i] == -1
。 -
如果
rains[i] == 0
,ans[i] 是你第 i 天选择抽干的湖泊。
如果有多种可行解,请返回它们中的 任意一个 。如果没办法阻止洪水,请返回一个 空的数组 。
请注意,如果你选择抽干一个装满水的湖泊,它会变成一个空的湖泊。但如果你选择抽干一个空的湖泊,那么将无事发生(详情请看示例 4)。
示例:
输入:rains = [1,2,3,4]
输出:[-1,-1,-1,-1]
解释:第一天后,装满水的湖泊包括 [1]
第二天后,装满水的湖泊包括 [1,2]
第三天后,装满水的湖泊包括 [1,2,3]
第四天后,装满水的湖泊包括 [1,2,3,4]
没有哪一天你可以抽干任何湖泊的水,也没有湖泊会发生洪水。输入:rains = [1,2,0,0,2,1]
输出:[-1,-1,2,1,-1,-1]
解释:第一天后,装满水的湖泊包括 [1]
第二天后,装满水的湖泊包括 [1,2]
第三天后,我们抽干湖泊 2 。所以剩下装满水的湖泊包括 [1]
第四天后,我们抽干湖泊 1 。所以暂时没有装满水的湖泊了。
第五天后,装满水的湖泊包括 [2]。
第六天后,装满水的湖泊包括 [1,2]。
可以看出,这个方案下不会有洪水发生。同时, [-1,-1,1,2,-1,-1] 也是另一个可行的没有洪水的方案。输入:rains = [1,2,0,1,2]
输出:[]
解释:第二天后,装满水的湖泊包括 [1,2]。我们可以在第三天抽干一个湖泊的水。
但第三天后,湖泊 1 和 2 都会再次下雨,所以不管我们第三天抽干哪个湖泊的水,另一个湖泊都会发生洪水。
分析:
双端队列 + 哈希表。具体代码看了一个大佬的题解,我又补充了一些注释。注释分析的已经很不错了,之后再补充一些分析和总结。
代码(Python):
class Solution:
def avoidFlood(self, rains: List[int]) -> list[int]:
# 使用deque可以确保日期小的在前面
lake_to_days = defaultdict(deque)
for date, lake in enumerate(rains):
if lake != 0:
lake_to_days[lake].append(date)
q = []
full = set()
res = []
for date, lake in enumerate(rains):
if lake != 0:
# 当前湖已经满了,无法避免洪水
if lake in full:
return []
else:
# 依题意,如果该天下雨,不可以抽水
res.append(-1)
# 将当前湖加入full
full.add(lake)
# 左侧的第一个日期就是该日期,所以删除
lake_to_days[lake].popleft()
# 如果该湖之后还要下雨,将日期加入优先队列中
if lake_to_days[lake]:
hq.heappush(q, lake_to_days[lake][0])
else:
# 优先队列为空,且根据题目要求rains[i] == 0,需排水,因此随便抽一个湖即可
if not q:
res.append(1)
# 选取优先队列中最小的日期,将在该日期下雨的湖抽干
else:
date = hq.heappop(q)
res.append(rains[date])
full.remove(rains[date])
return res