LeetCode 401 二进制手表
题目描述
二进制手表顶部有 4 个 LED 代表小时(0-11),6 个 LED 代表分钟(0-59)。每个 LED 亮表示对应位为 1。给定一个整数 turnedOn 表示当前亮着的 LED 的数量,返回所有可能表示的时间。你可以按任意顺序返回答案。
小时不会以零开头,例如 "01:00" 是无效的,应为 "1:00"。分钟必须由两位数组成,例如 "10:2" 是无效的,应为 "10:02"。
解题思路
本题可以采用二进制枚举的方法。总共有 10 个 LED,每个 LED 只有亮(1)和灭(0)两种状态,因此所有可能的亮灭组合共有 (2^{10} = 1024) 种。我们可以枚举所有组合,即枚举 0 到 1023 的整数,每个整数的二进制表示恰好对应一种 LED 状态。
- 高 4 位(从右向左第 6 位到第 9 位)代表小时(0~11)。
- 低 6 位(第 0 位到第 5 位)代表分钟(0~59)。
对于每个枚举值 i,我们需要:
- 统计二进制中 1 的个数,即亮着的 LED 数量
s。 - 如果
s等于turnedOn,则进一步分离出小时和分钟:- 小时
a = i >> 6(右移 6 位,得到高 4 位) - 分钟
b = i & 0b111111(按位与 63,保留低 6 位)
- 小时
- 检查
a是否在 0~11 之间,b是否在 0~59 之间,若是则格式化时间存入结果。
该算法简单直接,无需复杂剪枝,且枚举量很小,效率很高。
代码实现
cpp
class Solution {
public:
vector<string> readBinaryWatch(int turnedOn) {
vector<string> res; // 存储结果的字符串数组
char str[10]; // 临时字符数组,用于格式化时间
// 枚举所有可能的 10 位二进制数,范围 0 到 1023
for (int i = 0; i < (1 << 10); i++) {
int s = 0; // 统计亮灯数量
// 逐位检查是否为 1
for (int j = 0; j < 10; j++) {
if (i >> j & 1) {
s++;
}
}
// 如果亮灯数量等于要求,则处理这个组合
if (s == turnedOn) {
int hour = i >> 6; // 高 4 位作为小时
int minute = i & 63; // 低 6 位作为分钟 (63 = 0b111111)
// 检查合法性
if (hour < 12 && minute < 60) {
sprintf(str, "%d:%02d", hour, minute);
res.push_back(str);
}
}
}
return res;
}
};
代码逐行详解
vector<string> res;:定义一个字符串向量,用于存放最终结果。char str[10];:C 风格字符数组,配合sprintf使用,确保有足够空间存放格式化后的时间字符串(如"11:59"长度为 5,加上\0共 6 字节,10 足够)。- 外层循环
for (int i = 0; i < (1 << 10); i++):遍历 0 到 1023 的所有整数,每个整数对应一种 LED 亮灭状态。1 << 10是 1024。 int s = 0;:计数器,记录当前状态i中 1 的个数。- 内层循环
for (int j = 0; j < 10; j++):遍历 10 个二进制位。if (i >> j & 1):右移j位后与 1 按位与,判断第j位是否为 1。注意这里j从 0 开始,即从最低位开始判断,但顺序不影响计数结果。s++:如果为 1,计数器加一。
if (s == turnedOn):只有当亮灯数量等于题目要求时,才进一步处理。int hour = i >> 6;:将i右移 6 位,得到高 4 位。例如i的二进制为hhhh mmmmmm(h 表示小时位,m 表示分钟位),右移 6 位后得到hhhh,即为小时值。int minute = i & 63;:按位与 63(二进制 111111),得到低 6 位,即为分钟值。if (hour < 12 && minute < 60):判断小时和分钟是否合法(小时范围 0~11,分钟范围 0~59)。sprintf(str, "%d:%02d", hour, minute);:格式化字符串。%d输出小时无前导零,%02d输出分钟,保证两位,不足补零。res.push_back(str);:将格式化后的字符串存入结果向量。- 循环结束后返回
res。
复杂度分析
- 时间复杂度 :外层循环执行 (2^{10}=1024) 次,内层循环每次固定执行 10 次,所以总操作次数约为 (1024 \times 10 = 10240),可以视为常数时间。因此时间复杂度为 O(1)。
- 空间复杂度 :除了存储答案的向量外,只使用了常数个变量,空间复杂度为 O(1)(不计输出空间)。
总结
本题解利用了二进制枚举的思想,将 LED 状态映射为整数的二进制位,直接遍历所有组合并筛选。这种方法简单易懂,代码简洁,非常适合初学者理解二进制表示和位运算。同时,由于总状态数固定,效率也非常高。