[英雄星球六月集训LeetCode解题日报] 第17日 宽搜
日报
- 今天出去忙了一天,晚上回来再开始补作业。
- 还好题目不是很难。
- 每日一题也是easy。
题目
一、 2059. 转化数字的最小运算数
链接: 2059. 转化数字的最小运算数
1. 题目描述
给你一个下标从 0 开始的整数数组 nums ,该数组由 互不相同 的数字组成。另给你两个整数 start 和 goal 。
整数 x 的值最开始设为 start ,你打算执行一些运算使 x 转化为 goal 。你可以对数字 x 重复执行下述运算:
如果 0 <= x <= 1000 ,那么,对于数组中的任一下标 i(0 <= i < nums.length),可以将 x 设为下述任一值:
x + nums[i]
x - nums[i]
x ^ nums[i](按位异或 XOR)
注意,你可以按任意顺序使用每个 nums[i] 任意次。使 x 越过 0 <= x <= 1000 范围的运算同样可以生效,但该该运算执行后将不能执行其他运算。
返回将 x = start 转化为 goal 的最小操作数;如果无法完成转化,则返回 -1
2. 思路分析
没什么好思路,就层先暴搜吧~
- 每一步操作数是3,按理说应该封一下数组,但是我困了,就在搜索里边复制三遍代码吧~
- 起始状态start,目标goal,题目要求中间步不能超范围,但goal可以,那么在状态监测入队之前判断goal即可。
- 用层先先法,记录step,就可以不用给每个状态记步数啦。
- 就还挺快。
3. 代码实现
class Solution:
def minimumOperations(self, nums: List[int], start: int, goal: int) -> int:
step = 0
q = deque([start])
visited = {start}
while q:
step += 1
new_q = deque()
while q:
cur = q.popleft()
for num in nums:
nxt = cur - num
if nxt == goal:
return step
if 0<=nxt<=1000 and nxt not in visited:
new_q.append(nxt)
visited.add(nxt)
nxt = cur + num
if nxt == goal:
return step
if 0<=nxt<=1000 and nxt not in visited:
new_q.append(nxt)
visited.add(nxt)
nxt = cur ^ num
if nxt == goal:
return step
if 0<=nxt<=1000 and nxt not in visited:
new_q.append(nxt)
visited.add(nxt)
q = new_q
return -1
二、 690. 员工的重要性
链接: 690. 员工的重要性
1. 题目描述
给定一个保存员工信息的数据结构,它包含了员工 唯一的 id ,重要度 和 直系下属的 id 。
比如,员工 1 是员工 2 的领导,员工 2 是员工 3 的领导。他们相应的重要度为 15 , 10 , 5 。那么员工 1 的数据结构是 [1, 15, [2]] ,员工 2的 数据结构是 [2, 10, [3]] ,员工 3 的数据结构是 [3, 5, []] 。注意虽然员工 3 也是员工 1 的一个下属,但是由于 并不是直系 下属,因此没有体现在员工 1 的数据结构中。
现在输入一个公司的所有员工信息,以及单个员工 id ,返回这个员工和他所有下属的重要度之和。
2. 思路分析
这不就是个n叉树求某颗子树的权和么。懒得建树,用哈希表模拟关系建图dfs完事。
3. 代码实现
class Solution:
def getImportance(self, employees: List['Employee'], id: int) -> int:
# dfs暴搜
important = {e.id:e.importance for e in employees}
leadwho = {e.id:e.subordinates for e in employees}
def dfs(i):
ret = important[i]
if leadwho[i]:
ret += sum(dfs(j) for j in leadwho[i])
return ret
return dfs(id)
三、 672. 灯泡开关 Ⅱ
链接: 672. 灯泡开关 Ⅱ
1. 题目描述
现有一个房间,墙上挂有 n 只已经打开的灯泡和 4 个按钮。在进行了 m 次未知操作后,你需要返回这 n 只灯泡可能有多少种不同的状态。
假设这 n 只灯泡被编号为 [1, 2, 3 …, n],这 4 个按钮的功能如下:
- 将所有灯泡的状态反转(即开变为关,关变为开)
- 将编号为偶数的灯泡的状态反转
- 将编号为奇数的灯泡的状态反转
- 将编号为 3k+1 的灯泡的状态反转(k = 0, 1, 2, …)
2. 思路分析
先找规律:
- 发现本题循环节是6,所以n可以min(n,6)
- 操作就是异或,预处理一下每次的操作,共四种。
- 初始状态全1(全亮)
- 然后层先暴搜m次。
- 这里因为是求不同状态数,因此可以用set当q,不过我顺手用了q,反正层先也得再开个集合,就顺手用了。
- m次后len(q)就是答案。
3. 代码实现
class Solution:
def flipLights(self, n: int, presses: int) -> int:
"""
本题循环节是6,n可以状压6位二进制当状态。
每种操作,执行两次等于没执行,因此m其实也可以压缩,不过我有点困先不琢磨了
"""
ans = set()
n = min(n,6)
odd=even=k31=0
for i in range(n):
if i&1 == 0:
odd |= 1<<i
if i&1 == 1:
even |= 1<<i
if i%3 == 0:
k31 |= 1<<i
operate = [odd,even,k31,(1<<n)-1]
cur = (1<<n) - 1
# print(n,cur,operate)
q = deque([cur])
for i in range(presses):
cur_set = set()
while q:
cur = q.popleft()
for op in operate:
nxt = cur^op
cur_set.add(nxt)
# print(cur,op,cur_set)
q = deque(cur_set)
return len(q)