房间中有 n 只已经打开的灯泡,编号从 1 到 n 。墙上挂着 4 个开关 。
这 4 个开关各自都具有不同的功能,其中:
开关 1 :反转当前所有灯的状态(即开变为关,关变为开) 开关 2 :反转编号为偶数的灯的状态(即 2, 4, …) 开关 3
:反转编号为奇数的灯的状态(即 1, 3, …) 开关 4 :反转编号为 j = 3k + 1 的灯的状态,其中 k = 0, 1,
2, …(即 1, 4, 7, 10, …) 你必须 恰好 按压开关 presses 次。每次按压,你都需要从 4
个开关中选出一个来执行按压操作。给你两个整数 n 和 presses ,执行完所有按压之后,返回 不同可能状态 的数量。
来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/bulb-switcher-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 提示:1 <= n <= 1000 0 <= presses <= 1000
一开始写了一个最简单的未剪枝的dfs方法梳理思路
class Solution:
def flipLights(self, n: int, presses: int) -> int:
if presses==0:
return 1
ans = set()
def flip_1(state):
for id, num in enumerate(state):
state[id] = "1" if state[id] == "0" else "0"
# print(state)
return "".join(state)
def flip_2(state):
for id, num in enumerate(state):
if id%2 == 1:
state[id] = "1" if state[id] == "0" else "0"
# print(state)
return "".join(state)
def flip_3(state):
for id, num in enumerate(state):
if id%2 == 0:
state[id] = "1" if state[id] == "0" else "0"
# print(state)
return "".join(state)
def flip_4(state):
for id, num in enumerate(state):
if id%3 == 0:
state[id] = "1" if state[id] == "0" else "0"
# print(state)
return "".join(state)
def flips(states, press):
nonlocal ans
state = list(states)
if press == 1:
ans.add(flip_1(state))
ans.add(flip_2(state))
ans.add(flip_3(state))
ans.add(flip_4(state))
else:
flips(flip_1(state), press-1)
flips(flip_2(state), press-1)
flips(flip_3(state), press-1)
flips(flip_4(state), press-1)
flips("0"*n, presses)
return len(ans)
时间复杂度:O( 4 p r e s s e s 4^{presses} 4presses)
空间复杂度:O( 4 n 4^n 4n)
明显可以看出在n和presses最高,可以达到1000时,是完全超时的,因此需要找到更简单的剪枝。
记四个操作分别为flip1到flip4,各类操作形成的符号串为
f
l
i
p
i
∗
f
l
i
p
j
⋯
∗
f
l
i
p
k
flipi*flipj\cdots*flipk
flipi∗flipj⋯∗flipk。我们很容易注意到 flip2和flip3是可交换的操作。因此经过仔细观察引申出来,所有的flip对于结果来说都是可交换的,因此我们只需要考虑
∏
i
1
+
i
2
+
i
3
+
i
4
=
p
r
o
c
e
s
s
e
s
(
f
l
i
p
1
)
i
1
(
f
l
i
p
2
)
i
2
(
f
l
i
p
3
)
i
3
(
f
l
i
p
4
)
i
4
\prod \limits_{i_1+i_2+i_3+i_4=processes} (flip1)^{i_1}(flip2)^{i_2}(flip3)^{i_3}(flip4)^{i_4}
i1+i2+i3+i4=processes∏(flip1)i1(flip2)i2(flip3)i3(flip4)i4的形式即可,又因为按钮操作本质上是一个可逆操作,其逆为本身,因此只需要关注
i
k
i_k
ik的奇偶性即可,因此形式转化为
∏
i
1
+
i
2
+
i
3
+
i
4
=
p
r
o
c
e
s
s
e
s
(
f
l
i
p
1
)
i
1
%
2
(
f
l
i
p
2
)
i
2
%
2
(
f
l
i
p
3
)
i
3
%
2
(
f
l
i
p
4
)
i
4
%
2
\prod \limits_{i_1+i_2+i_3+i_4=processes} (flip1)^{i_1\%2}(flip2)^{i_2\%2}(flip3)^{i_3\%2}(flip4)^{i_4\%2}
i1+i2+i3+i4=processes∏(flip1)i1%2(flip2)i2%2(flip3)i3%2(flip4)i4%2 而
f
l
i
p
2
∗
f
l
i
p
3
=
f
l
i
p
1
flip2*flip3=flip1
flip2∗flip3=flip1
因此我们得到最多只有8中情况,列出对应情况即可,为O(1)复杂度
class Solution:
def flipLights(self, n: int, presses: int) -> int:
if presses == 0:
return 1
if n > 2:
if presses == 1:
return 4
if presses == 2:
return 6 + 1
if presses == 3:
return 4 + 4
if presses == 4:
return 6 + 2
return comb(4, 2) + 2
elif n == 2:
if presses == 1:
return 3
if presses == 2:
return 3 + 1
if presses == 3:
return 3 + 1
return 4
return 2