问题描述
GA binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom represent the minutes (0-59).
Each LED represents a zero or one, with the least significant bit on the right.
For example, the above binary watch reads "3:25".
Given a non-negative integer n which represents the number of LEDs that are currently on, return all possible times the watch could represent.
Example:
Input: n = 1
Return: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"]
Note:
The order of output does not matter.
The hour must not contain a leading zero, for example "01:00" is not valid, it should be "1:00".
The minute must be consist of two digits and may contain a leading zero, for example "10:2" is not valid, it should be "10:02".
补充说明:
这个题目的大体意思是,有这么一个LED灯表示的表(如图示),上面4个LED表示时钟,下面6个LED表示分钟。灯亮表示对应的bit位为1。这些灯代表的bit位组合成的数字就是对应当前时间时钟数和分钟数(图上表示3:25)。现在需要你写一段代码,输入要亮灯的个数(不分时钟还是分钟),对应输出这些个数的灯能组成的所有时间。
这里还有一些小点需要注意:
- 输出的顺序无关紧要。
- 小时不能包含前导0,例如“01:00”无效,应为“1:00”。
- 分钟必须由两位数字组成,并且可能包含前0,例如“10:2”无效,应为“10:02”。
方案分析
- 这个问题都能一下子想到它的最简单解,就是遍历时钟和分钟数的每一个时间段,如果这两个数字里面包含的数字‘1’的
个数的总和为输入的数字。这显然是一个愚蠢的做法,因为这个循环会执行12 × 60次。
python实现
class Solution(object):
def readBinaryWatch(self, num):
return ['%d:%02d' % (h, m)
for h in range(12) for m in range(60)
if (bin(h) + bin(m)).count('1') == num]
方案分析2
- 上面的方式是最为传统的思想,那么有什么办法能提高一点执行速度么,于是找到了下面一种方法。这种方法采用了空间换时间的方式,先将小时和分钟的二进制表示中1的个数hash表保存起来(相当于自己实现了一个上面的
count(str)方法
)。这里比上面效率高的地方在于,它并不会执行12 × 60次,而是先保障时钟的循环次数的情况下,内部(循环num - 小时所用1的位数)次。
python实现2
class Solution(object):
# Binary Watch
def readBinaryWatch(self, num):
"""
:type num: int
:rtype: List[str]
"""
hourMap = {i: self.countOfBits(i) for i in range(12)}
minutesMap = {i: self.countOfBits(i) for i in range(60)}
res = []
for hour in filter(lambda x: hourMap[x] <= num, range(12)):
res += ["%s" % hour + ":" + ("%s" % minute).zfill(2) for minute in filter(lambda x: minutesMap[x] == num - hourMap[hour], range(60))]
return res
def countOfBits(self, num):
counter = 0
while num:
counter += 1
num &= num - 1
return counter
方案分析3
- 绕过上面两种思路,我们再想想还有其他方式吗?这里一共有10个LED,如果我们不关注它表示的是否是小时位还是分钟位,那么这个问题是不是就变为了让指定个数的位置的灯亮起或者熄灭的排列组合问题了。
- 这里除了排列组合这个问题,还需要注意的是,并不是所有的组合都对应存在的时间,可能会出现不合理的时间。比如很明显10个LED全部亮起就不是一个合理的时间。
python实现3
class Solution(object):
def readBinaryWatch(self, num):
"""
:type num: int
:rtype: List[str]
"""
res = []
if num > 10 or num < 0:
return res
for comb in itertools.combinations(range(10), num):
h = int("".join(['1' if i in comb
else '0'
for i in range(4)]), 2)
m = int("".join(['1' if i in comb
else '0'
for i in range(4, 10)]), 2)
if h < 12 and m < 60:
res.append(str(h) + ":" + str(m).zfill(2))
return res