0401-二进制手表

Raphael Liu Lv10

二进制手表顶部有 4 个 LED 代表 小时(0-11) ,底部的 6 个 LED 代表 分钟(0-59) 。每个 LED 代表一个 0 或
1,最低位在右侧。

  • 例如,下面的二进制手表读取 "4:51"

给你一个整数 turnedOn ,表示当前亮着的 LED 的数量,返回二进制手表可以表示的所有可能时间。你可以 按任意顺序 返回答案。

小时不会以零开头:

  • 例如,"01:00" 是无效的时间,正确的写法应该是 "1:00"

分钟必须由两位数组成,可能会以零开头:

  • 例如,"10:2" 是无效的时间,正确的写法应该是 "10:02"

示例 1:

**输入:** turnedOn = 1
**输出:** ["0:01","0:02","0:04","0:08","0:16","0:32","1:00","2:00","4:00","8:00"]

示例 2:

**输入:** turnedOn = 9
**输出:** []

提示:

  • 0 <= turnedOn <= 10

方法一:枚举时分

由题意可知,小时由 $4$ 个比特表示,分钟由 $6$ 个比特表示,比特位值为 $0$ 表示灯灭,为 $1$ 表示灯亮。

我们可以枚举小时的所有可能值 $[0,11]$,以及分钟的所有可能值 $[0,59]$,并计算二者的二进制中 $1$ 的个数之和,若为 turnedOn,则将其加入到答案中。

[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<string> readBinaryWatch(int turnedOn) {
vector<string> ans;
for (int h = 0; h < 12; ++h) {
for (int m = 0; m < 60; ++m) {
if (__builtin_popcount(h) + __builtin_popcount(m) == turnedOn) {
ans.push_back(to_string(h) + ":" + (m < 10 ? "0" : "") + to_string(m));
}
}
}
return ans;
}
};
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public List<String> readBinaryWatch(int turnedOn) {
List<String> ans = new ArrayList<String>();
for (int h = 0; h < 12; ++h) {
for (int m = 0; m < 60; ++m) {
if (Integer.bitCount(h) + Integer.bitCount(m) == turnedOn) {
ans.add(h + ":" + (m < 10 ? "0" : "") + m);
}
}
}
return ans;
}
}
[sol1-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Solution {
public IList<string> ReadBinaryWatch(int turnedOn) {
IList<String> ans = new List<String>();
for (int h = 0; h < 12; ++h) {
for (int m = 0; m < 60; ++m) {
if (BitCount(h) + BitCount(m) == turnedOn) {
ans.Add(h + ":" + (m < 10 ? "0" : "") + m);
}
}
}
return ans;
}

private static int BitCount(int i) {
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i + (i >> 4)) & 0x0f0f0f0f;
i = i + (i >> 8);
i = i + (i >> 16);
return i & 0x3f;
}
}
[sol1-Golang]
1
2
3
4
5
6
7
8
9
10
func readBinaryWatch(turnedOn int) (ans []string) {
for h := uint8(0); h < 12; h++ {
for m := uint8(0); m < 60; m++ {
if bits.OnesCount8(h)+bits.OnesCount8(m) == turnedOn {
ans = append(ans, fmt.Sprintf("%d:%02d", h, m))
}
}
}
return
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
var readBinaryWatch = function(turnedOn) {
const ans = [];
for (let h = 0; h < 12; ++h) {
for (let m = 0; m < 60; ++m) {
if (h.toString(2).split('0').join('').length + m.toString(2).split('0').join('').length === turnedOn) {
ans.push(h + ":" + (m < 10 ? "0" : "") + m);
}
}
}
return ans;
};
[sol1-Python3]
1
2
3
4
5
6
7
8
class Solution:
def readBinaryWatch(self, turnedOn: int) -> List[str]:
ans = list()
for h in range(12):
for m in range(60):
if bin(h).count("1") + bin(m).count("1") == turnedOn:
ans.append(f"{h}:{m:02d}")
return ans
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
char** readBinaryWatch(int turnedOn, int* returnSize) {
char** ans = malloc(sizeof(char*) * 12 * 60);
*returnSize = 0;
for (int h = 0; h < 12; ++h) {
for (int m = 0; m < 60; ++m) {
if (__builtin_popcount(h) + __builtin_popcount(m) == turnedOn) {
char* tmp = malloc(sizeof(char) * 6);
sprintf(tmp, "%d:%02d", h, m);
ans[(*returnSize)++] = tmp;
}
}
}
return ans;
}

复杂度分析

  • 时间复杂度:$O(1)$。枚举的次数是一个与输入无关的定值。

  • 空间复杂度:$O(1)$。仅使用了常数大小的空间。注意返回值不计入空间复杂度。

方法二:二进制枚举

另一种枚举方法是枚举所有 $2^{10}=1024$ 种灯的开闭组合,即用一个二进制数表示灯的开闭,其高 $4$ 位为小时,低 $6$ 位为分钟。若小时和分钟的值均在合法范围内,且二进制中 $1$ 的个数为 turnedOn,则将其加入到答案中。

[sol2-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
vector<string> readBinaryWatch(int turnedOn) {
vector<string> ans;
for (int i = 0; i < 1024; ++i) {
int h = i >> 6, m = i & 63; // 用位运算取出高 4 位和低 6 位
if (h < 12 && m < 60 && __builtin_popcount(i) == turnedOn) {
ans.push_back(to_string(h) + ":" + (m < 10 ? "0" : "") + to_string(m));
}
}
return ans;
}
};
[sol2-Java]
1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public List<String> readBinaryWatch(int turnedOn) {
List<String> ans = new ArrayList<String>();
for (int i = 0; i < 1024; ++i) {
int h = i >> 6, m = i & 63; // 用位运算取出高 4 位和低 6 位
if (h < 12 && m < 60 && Integer.bitCount(i) == turnedOn) {
ans.add(h + ":" + (m < 10 ? "0" : "") + m);
}
}
return ans;
}
}
[sol2-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Solution {
public IList<string> ReadBinaryWatch(int turnedOn) {
IList<String> ans = new List<String>();
for (int i = 0; i < 1024; ++i) {
int h = i >> 6, m = i & 63; // 用位运算取出高 4 位和低 6 位
if (h < 12 && m < 60 && BitCount(i) == turnedOn) {
ans.Add(h + ":" + (m < 10 ? "0" : "") + m);
}
}
return ans;
}

private static int BitCount(int i) {
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i + (i >> 4)) & 0x0f0f0f0f;
i = i + (i >> 8);
i = i + (i >> 16);
return i & 0x3f;
}
}
[sol2-Golang]
1
2
3
4
5
6
7
8
9
func readBinaryWatch(turnedOn int) (ans []string) {
for i := 0; i < 1024; i++ {
h, m := i>>6, i&63 // 用位运算取出高 4 位和低 6 位
if h < 12 && m < 60 && bits.OnesCount(uint(i)) == turnedOn {
ans = append(ans, fmt.Sprintf("%d:%02d", h, m))
}
}
return
}
[sol2-JavaScript]
1
2
3
4
5
6
7
8
9
10
var readBinaryWatch = function(turnedOn) {
const ans = [];
for (let i = 0; i < 1024; ++i) {
let h = i >> 6, m = i & 63; // 用位运算取出高 4 位和低 6 位
if (h < 12 && m < 60 && i.toString(2).split('0').join('').length === turnedOn) {
ans.push(h + ":" + (m < 10 ? "0" : "") + m);
}
}
return ans;
};
[sol2-Python3]
1
2
3
4
5
6
7
8
class Solution:
def readBinaryWatch(self, turnedOn: int) -> List[str]:
ans = list()
for i in range(1024):
h, m = i >> 6, i & 0x3f # 用位运算取出高 4 位和低 6 位
if h < 12 and m < 60 and bin(i).count("1") == turnedOn:
ans.append(f"{h}:{m:02d}")
return ans
[sol2-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
char** readBinaryWatch(int turnedOn, int* returnSize) {
char** ans = malloc(sizeof(char*) * 12 * 60);
*returnSize = 0;
for (int i = 0; i < 1024; ++i) {
int h = i >> 6, m = i & 63; // 用位运算取出高 4 位和低 6 位
if (h < 12 && m < 60 && __builtin_popcount(i) == turnedOn) {
char* tmp = malloc(sizeof(char) * 6);
sprintf(tmp, "%d:%02d", h, m);
ans[(*returnSize)++] = tmp;
}
}

return ans;
}

复杂度分析

  • 时间复杂度:$O(1)$。枚举的次数是一个与输入无关的定值。

  • 空间复杂度:$O(1)$。仅使用了常数大小的空间。注意返回值不计入空间复杂度。

本题还有利用位运算,枚举恰好有 turnedOn 个 $1$ 的二进制数的方法,但超出了这篇题解的范围,有兴趣的读者可自行查阅相关资料。

 Comments
On this page
0401-二进制手表