谷歌面试题 | 灯泡开关2

1,491 阅读6分钟

专栏 | 九章算法
网址 | www.jiuzhang.com

题目描述

房间里有n盏灯,初始时全是亮的,房间的墙上有4个按钮。问在按了恰好m次按钮后,n盏灯的状态共有多少种可能,返回这个值。

设n盏灯的标号[1,2,3,……,n],4个按钮的功能如下:
i.反转所有灯的状态。
ii.反转所有偶数标号的灯的状态。
iii.反转所有奇数标号的灯的状态。
iv.反转所有形如(3*k+1)标号的灯的状态,k=0,1,2,……。

样例1

i.输入: n = 1, m = 1
ii.输出: 2
iii.说明: 1盏灯按1次按钮后可能的状态为【亮】、【灭】。

样例2

i.输入: n = 2, m = 1
ii.输出: 3
iii.说明: 2盏灯按1次按钮后可能的状态为【灭,灭】、【亮,灭】、【灭、亮】。

样例3

i.输入: n = 3, m= 1
ii.输出: 4
iii.说明: 3盏灯按1次按钮后可能的状态为【灭,灭,灭】、【亮,灭,亮】、【灭,亮,灭】、【灭,亮,亮】。

注意:n和m的范围都在[0,1000]中。

解题思路分析

显然,直接枚举每一次的按钮是4个中的哪个的时间复杂度是指数级别的,事实上,为了判断最后得到的状态是否重复,可能还要用hashtable判重。

我们从两个方向对问题进行化简:

Ⅰ. 一是灯泡的周期性,先假设灯有足够多,考虑如果只有按钮1,即反转所有灯泡的状态,那么尽管n个灯泡最多会有2^n种状态,但是在初始状态确定为全亮的情况下,不论按钮1按几下,至多只有两种可能:全亮或全灭。如果将按钮2和按钮3考虑进来,也可以发现,无论怎么按按钮,奇数标号的灯状态都一样,偶数标号的灯状态都一样,最后的灯的状态是以2为周期的。现在考虑所有的4个按钮,无论怎么按,最后灯泡的状态应该是以6为周期的。因此,即使灯泡再多,也只需考虑前6个灯泡,其状态不会超过2^6=64种。这样,判重就不需要hashtable了,只需一个长为64的布尔型数组就可以了。

Ⅱ. 二是按钮的冗余性,首先,按按钮的顺序是可以交换而不改变结果的(如果把灯泡状态看成是一个二进制数的话,按按钮相当于按位异或某个数,而异或是满足交换律的),其次,同一个按钮按多次其实只有奇偶之分,也就是只有按与不按之分(连续按两次相当于不按,连续按三次又相当于按1次)。另外,按钮1、按钮2、按钮3中的其中两个是可以替代另一个的(或称线性相关),也就是说按这三个按钮中的任意两个按钮一下,相当于按另一个按钮一下。因此,4个按钮中有效的只有3个,3个按钮各自按与不按有两种情况,最后可能的状态数不会超过2^3=8种,而且这八种按按钮的方案最后得到的灯的状态(在灯足够多的情况下)是各不相同的。当m>=3时,这8种可能都是可以实现的,这并不是因为2^m>=8,(事实上,如果只有按钮2、3、4,而且m=3的话,是没法做到最后灯全亮即所有状态不变的,只要m为奇数,就不可能实现,但有4个按钮的话就做的到,只需按下按钮1、2、3即可),而是因为按钮1、2、3之间的替代关系,才使得这能成立。(可以动笔试试m=3和m=4的情况下如何得到所有的八种情况,对于m>=5的情况,只要从m=3或m=4的情况下增加偶数次按同一个按钮即可得到)。

Ⅲ. 这样一来就可以得到相对合理的算法:如果m>=3,就枚举按钮2,3,4(前3个按钮可任取两个)按与不按得到八种情况,看这八种情况中不重复的有几种;如果m<3,可以直接枚举按每一次按的是4个中的哪一个,然后判重得到答案。由于涉及的数都比较小,虽然时间复杂度不是常数,但实际肯定不会有太大的耗时。

由于涉及到的数都比较小,那么我们就直接来看看各种情况下的答案吧。首先我们用一个6位的二进制数来表示灯的状态,0表示某一位的灯亮,1表示灯灭,由于灯的状态一定会以6为周期,所以只看6位,暂时先不考虑灯泡数量。初始状态为000000,按一次按钮1变为111111,;按一次按钮2变为010101,;按一次按钮3变为101010;按一次按钮4变为100100。

i. m>=3时,总共有8种可能,即000000、001110、010101、011011、100100、101010、110001、111111。如果n=1,可以只看第1位,有0和1两种可能;如果n=2,看前两位,有00、01、10、11四种可能;如果n>=3,所有8种可能都互不相同。

ii. m=1时,按一次开关有4种可能,且这4种可能各不相同:111111、010101、101010、100100。如果n=1,看第1位,有0和1两种可能;如果n=2,看前两位,最后两种是一样的,有11、01、10三种可能;如果n>=3,那么就有所有4种可能。

iii. m=2时。按两次开关有16种可能,但不同的只有7种:000000、001110、010101、011011、101010、110001、111111。如果n=1,看第一位,有0和1两种可能;如果n=2,看前两位,有00、01、10、11四种可能;如果n>=3,所有7种可能都互不相同。

参考程序

Bulb Switcher-ii 参考程序

面试官角度分析

这题乍一看可能会感觉答案会很大,但实际分析后就可以发现状态数其实是很小的,关键在于如何剔除多余的状态。给出正确的算法即可hire。

lintcode相关问题

Bit Manipulation


推荐阅读



欢迎关注我的微信公众号:九章算法(ninechapter)。
精英程序员交流社区,定期发布面试题、面试技巧、求职信息等

九章算法,IT教育领域的深耕者
九章算法,IT教育领域的深耕者