1. 程式人生 > >LeetCode演算法題-Binary Watch(Java實現)

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+篇,公眾號對話方塊回覆【資料結構與演算法】、【演算法】、【資料結構】中的任一關鍵詞,獲取系列文章合集。

以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!