LeetCode演算法題-Binary Watch(Java實現)
這是悅樂書的第216次更新,第229篇原創
01 看題和準備
今天介紹的是LeetCode演算法題中Easy級別的第84題(順位題號是401)。二進位制手錶頂部有4個LED,代表小時(0-11),底部的6個LED代表分鐘(0-59)。每個LED代表一個零或一個,右側的最低有效位。給定非負整數n表示當前開啟的LED數量,返回手錶可能代表的所有可能時間。例如:
輸入:n = 1
輸出:[“1:00”,“2:00”,“4:00”,“8:00”,“0:01”,“0:02”,“0:04”,“0:08” ,“0:16”,“0:32”]
注意:
- 輸出順序無關緊要。
- 小時不得包含前導零,例如“01:00”無效,應為“1:00”。
- 分鐘必須由兩位陣列成,並且可能包含前導零,例如“10:2”無效,應為“10:02”。
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 第一種解法
代表小時的有四個燈,代表分鐘的有六個燈,傳入的引數num就是小時加分鐘所代表的亮燈數之和,所以只要小時加分鐘的亮燈數等於num,就代表可能的一種時間。可以聯想到使用位操作,亮就表示1,不亮就表示0,因為只要計算1的位數等於num即可。使用兩層迴圈,外層迴圈是小時,從0到11,內層迴圈是分鐘,從0到59,如果小時加分鐘的二進位制1位計數之和等於num,就將其新增進list中。
public List<String> readBinaryWatch(int num) { List<String> list = new ArrayList<String>(); for (int i=0; i<12; i++) { for (int j=0; j<60; j++) { if (Integer.bitCount(i)+Integer.bitCount(j) == num) { String answer = ""; if (j < 10) { answer = i + ":0" + j; } else { answer = i + ":" + j; } list.add(answer); } } } return list; }
03 第二種解法
此題也可以理解為從n個數中取出k個數的問題,小時有四個數,分鐘有六個數,要從這10個數中取出num個數來,組合成滿足條件的時間。比如,num等於2,那麼從小時中就可以取1次,剩下的1次在分鐘裡取,也可以全部在小時裡取,也可以全部在分鐘中取,只要次數不超過num即可。同時,要先將兩種特殊情況排除出去。
public List<String> readBinaryWatch2(int num) { List<String> list = new ArrayList<String>(); if (num == 0) { list.add("0:00"); return list; } if (num > 8) { return list; } int[] temp = {8,4,2,1,32,16,8,4,2,1}; boolean[] index = new boolean[10]; helperFun(list, temp, index, num, 0); return list; } void helperFun(List<String> list, int[] temp, boolean[] index, int num, int start){ if (num == 0) { int hour = 0; int minute = 0; for (int k = 0; k < 10; k++) { if (index[k] == true && k <= 3) { hour += temp[k]; } if (index[k] == true && k > 3) { minute += temp[k]; } } if (hour >= 12 || minute >= 60) { return; } else { String answer = ""; if (minute < 10) { answer = hour + ":0" + minute; } else { answer = hour + ":" + minute; } list.add(answer); return; } } for (int i = start; i < temp.length; i++) { index[i] = true; helperFun(list, temp, index, num - 1, i + 1); index[i] = false; } }
04 第三種解法
思路和第二種解法類似,但是要比第二種解法精簡些。我們將表示小時和分鐘的陣列設定為全域性變數,這樣就不必在遞迴的方法裡面每次都傳入,並且還要判斷使用過沒有,使用一個指標來幫助我們判斷即可,當指標小於4的時候,都是在小時中取,所以小時需要加上陣列中新的小時數,而分鐘不變,當指標大於等於4的時候,就是在分鐘裡取,所以分鐘要加上陣列中新的分鐘數,而小時不變。而num是一直在遞減的。當小時大於11或者分鐘大於59時,直接return,這是遞迴的結束條件。
private int[] all = {1,2,4,8,1,2,4,8,16,32};
public List<String> readBinaryWatch3(int num) {
List<String> list = new ArrayList<String>();
helperFun(list, num, 0, 0, 0);
return list;
}
void helperFun(List<String> list, int num, int hour, int minute, int index) {
if (hour > 11 || minute > 59) {
return;
}
if (num == 0) {
String answer = "";
if (minute < 10) {
answer = hour + ":0" + minute;
} else {
answer = hour + ":" + minute;
}
list.add(answer);
}
for (int i=index; i<10; i++) {
if (i < 4) {
helperFun(list, num-1, hour+all[i], minute, i+1);
} else {
helperFun(list, num-1, hour, minute+all[i], i+1);
}
}
}
05 小結
演算法專題目前已連續日更超過兩個月,演算法題文章84+篇,公眾號對話方塊回覆【資料結構與演算法】、【演算法】、【資料結構】中的任一關鍵詞,獲取系列文章合集。
以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!