问题描述
二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。
给定一个非负整数 n 代表当前 LED 亮着的数量,返回所有可能的时间。
解法一:暴力求解
利用两个for循环可以得到从0:00到11:59之间的所有时间,根据手表的特性,上方有LED的亮灯数表示了该时间所对应的二进制数有多少个1,因此可以采用java语法中Integer的方法bitCount,该方法可以返回一个整数转二进制后1的个数,当上方1的个数+下方1的个数==n的时候,即为一个对应的时间。最后用String类中的方法format格式化输出即可。
代码如下:
class Solution {
public List<String> readBinaryWatch(int num) {
List<String> list =new ArrayList<>();
for(int i=0;i<12;i++){
for(int j=0;j<60;j++){
if(Integer.bitCount(i)+Integer.bitCount(j)==num)
//使用String类中的format格式化输出
list.add(String.format("%d:%02d",i,j));
}
}
return list;
}
}
算法分析:
时间复杂度:O(n²);
空间复杂度:O(n);
解法二:回溯求解
分析该问题:该二进制手表的灯数为10,可以用一个数组从0到9表示,当灯被点亮时,设置灯的值为1,熄灭时设置灯的值为0;
操作:在位置i上点亮一盏灯;
操作后得到的子问题:在位置i+1到9的位置点亮n-1盏灯;
递归的出口:当n==0时,表示n盏灯都已经点亮,得到一个最终解,判断该解是否符合条件,若符合,则递归终结,逐步返回,同时也逐步回溯,并把沿途点亮过的灯都熄灭。
代码如下:
class Solution {
List<String> list=new ArrayList<>();
public List<String> readBinaryWatch(int num) {
//用长度为10的数组表示10盏灯
dfs(num,0,new int [10]);
return list;
}
public void dfs(int num,int cur,int[] time){
if(num==0){
int hour=1*time[0]+2*time[1]+4*time[2]+8*time[3];
int minute=1*time[4]+2*time[5]+4*time[6]+8*time[7]+16*time[8]+32*time[9];
if(hour<12&&minute<60){
list.add(String.format("%d:%02d",hour,minute));
}
//找到符合条件的解,退出
return;
}
for(int i=cur;i<time.length;i++){
//点亮当前位置的灯
time[i]=1;
dfs(num-1,i+1,time);
//回溯
//将沿途点亮的灯熄灭
time[i]=0;
}
}
}
算法分析:
时间复杂度:O(n!);
空间复杂度:O(n);
关于回溯算法的基本思想:
回溯算法属于深度优先遍历思想的一种具体算法,从问题的根部出发,逐个探索结点,并同时判断该结点是否满足问题的解,若满足,则从该结点继续访问,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(实际上,回溯法在探索的过程中会用剪枝函数来避免无效的搜索)。
由于水平有限,文章难免可能存在偏差与漏洞,望各位路过大神指正。