A 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.
没有明确给出。
表示小时的数值只有0-11,表示分钟的数值只有0-59。我的思路是先分别对小时跟分钟的数值进行预处理,按照包含1的个数分开保存小时数值的字符串跟分钟数值的字符串。
以小时为例,小时使用4个位表示,最少包含0个1,最多包含3个1,所以用vector
建立一个包含4个vector的vector数组,hours[0]保存着0个1的数值对应的字符串”0”,hours[1]保存着有1个1的数值对应的字符串,即”1”,”2”,”4”,”8”,hours[2]保存着”3”,”5”,”6”,”9”,”10”,hours[3]保存着”7”,”11”。
对分钟数值的处理相似。
然后根据读入的num,设置小时包含的1的个数为i,分钟包含的个数则是num-i。从i=0开始,在满足i<4跟num-i<6的情况,拼接hours[i]和minues[num - i]的所有字符串,并将拼接后的字符串添加到结果数组中,最后返回结果即可通过。
我这种解法空间复杂度大,由于拼接使用了三重循环,所以时间复杂度也大,下面还是看看大牛们的解法吧,大的方向有两个,遍历跟回溯。
第一种是遍历,用到的是bitset这个C++ STL模板。
按照数值上分析,最多只有 12×60=720 种组合,所以只要遍历这720种组合,通过bitset的count函数判断各个组合的1的个数是否等于num,是则添加对应的时间字符串到结果数组中,最后返回结果数组即可。见参考代码1。
除了按数值上,也可以从二进制表示上遍历,由于小时有4位,分钟有6位,所以总共10位就可以表示所有的情况,最大的数值是0x2FF (1011 | 111111),所以遍历从0到0x2FF之间的数值,判断1的个数是否等于num,是则截取出小时和分钟,并拼接成字符串添加到结果数组。见参考代码2。
还有一种思路是使用递归进行回溯。核心思想是在每一次递归中,都分配一个1到某一位并把该位的数值添加到对应的小时或是分钟上,然后进入下一次递归,递归结束条件是没有更多的1可分配,此时把时间字符串添加到结果数组中。递归返回到上一层后,要回溯到分配1之前的状态,并把1分配给新的位,继续下一轮递归。具体实现见参考代码3,建议都在纸上演算一下,这样才能体会回溯的流程。
class Solution {
public:
vector<string> readBinaryWatch(int num) {
vector<vector<string>> hours(4);
vector<vector<string>> minutes(6);
vector<string> times;
for (int i = 0; i < 12; i++) {
char s[2];
sprintf(s, "%d", i);
hours[hammingWeight(i)].push_back(s);
}
for (int i = 0; i < 60; i++) {
char s[2];
sprintf(s, "%02d", i);
minutes[hammingWeight(i)].push_back(s);
}
for (int i = 0; i < 4 && i <= num; i++) {
if (num - i < 6)
for (auto& h: hours[i])
for (auto& s: minutes[num - i])
times.push_back(h + ":" + s);
}
return times;
}
static int hammingWeight(uint32_t n) {
int sum = 0;
while (n != 0) {
sum++;
n &= (n - 1);
}
return sum;
}
};
class Solution {
public:
vector<string> readBinaryWatch(int num) {
vector<string> times;
for (int i = 0; i < 12; i++) {
bitset<4> h((size_t) i);
for (int j = 0; j < 60; j++) {
bitset<6> m((size_t) j);
if (h.count() + m.count() == num)
times.push_back(to_string(i) + (j < 10? ":0": ":") + to_string(j));
}
}
return times;
}
};
class Solution {
public:
vector<string> readBinaryWatch(int num) {
vector<string> times;
if (num < 0 || num > 8)
return times;
for (int i = 0; i < 0x2FF; i++) {
if (bitset<10>(i).count() == num)
add(i, times);
}
return times;
}
void add(int i, vector<string>& t) {
string s;
int m = i & 0x3F;
if (m > 59)
return;
int h = i >> 6 & 0xF;
if (h > 11)
return;
t.push_back(to_string(h) + (m < 10? ":0" : ":") + to_string(m));
}
};
class Solution {
vector<int> hour = {1, 2, 4, 8}, minute = {1, 2, 4, 8, 16, 32};
public:
vector<string> readBinaryWatch(int num) {
vector<string> res;
helper(res, make_pair(0, 0), num, 0);
return res;
}
void helper(vector<string>& res, pair<int, int> time, int num, int start_point) {
if (num == 0) {
if (time.second < 10)
res.push_back(to_string(time.first) + ":0" + to_string(time.second));
else
res.push_back(to_string(time.first) + ":" + to_string(time.second));
return;
}
for (int i = start_point; i < hour.size() + minute.size(); i ++) {
if (i < hour.size()) {
time.first += hour[i];
if (time.first < 12) // "hour" should be less than 12.
helper(res, time, num - 1, i + 1);
time.first -= hour[i];
} else {
time.second += minute[i - hour.size()];
if (time.second < 60) // "minute" should be less than 60.
helper(res, time, num - 1, i + 1);
time.second -= minute[i - hour.size()];
}
}
}
};
这道题真的很不错,我花了不少时间去思考,虽然我自己想出来的解法不怎么好,但是在思考跟实现的过程中,我复习了很多遗忘的知识。然后还看了其他人实现的过程,学习了bitset的使用,还有回溯的思想,让我觉得真的是获益匪浅。
完成今天的坑了,假期里继续加油!