1. 程式人生 > >[LeetCode] 1-bit and 2-bit Characters 一位和兩位字元

[LeetCode] 1-bit and 2-bit Characters 一位和兩位字元

We have two special characters. The first character can be represented by one bit 0. The second character can be represented by two bits (10 or 11).

Now given a string represented by several bits. Return whether the last character must be a one-bit character or not. The given string will always end with a zero.

Example 1:

Input: 
bits = [1, 0, 0]
Output: True
Explanation: 
The only way to decode it is two-bit character and one-bit character. So the last character is one-bit character.

Example 2:

Input: 
bits = [1, 1, 1, 0]
Output: False
Explanation: 
The only way to decode it is two-bit character and two-bit character. So the last character is NOT one-bit character.

Note:

  • 1 <= len(bits) <= 1000.
  • bits[i] is always 0 or 1.

這道題說有兩種特殊的字元,一種是兩位字元,只能是二進位制的11和10,另一種是單個位字元,只能是二進位制的0。現在給了我們一個只包含0和1的陣列,問我們能否將其正確的分割,使得最後一個字元是個單個位字元。這道題可以使用貪婪演算法來做,因為兩種字元互不干擾,只要我們遍歷到了數字1,那麼其必定是兩位字元,所以後面一位也得跟著,而遍歷到了數字0,那麼就必定是單個位字元。所以我們可以用一個變數i來記錄當前遍歷到的位置,如果遇到了0,那麼i自增1,如果遇到了1,那麼i自增2,我們迴圈的條件是i < n-1,即留出最後一位,所以當迴圈退出後,當i正好停留在n-1上,說明最後一位是單獨分割開的,因為題目中限定了最後一位一定是0,所以沒必要再判斷了,參見程式碼如下:

解法一:

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        int n = bits.size(), i = 0;
        while (i < n - 1) {
            if (bits[i] == 0) ++i;
            else i+= 2;
        }
        return i == n - 1;
    }
};

下面這種解法寫的更加簡潔了,直接用一行代替了if..else..語句,相當巧妙,當bits[i]為0時,i還是相當於自增了1,當bits[i]為1時,i相當於自增了2,最後還是在迴圈跳出後檢測i是否為n-1,參見程式碼如下:

解法二:

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        int n = bits.size(), i = 0;
        while (i < n - 1) {
            i += bits[i] + 1;
        }
        return i == n - 1;
    }
};

下面我們來看遞迴解法,用的是回溯的思想,首先判斷如果bits為空了,直接返回false,因為題目初始給的bits是非空的,在呼叫遞迴函式中為空了說明最後一位跟倒數第二位組成了個兩位字元,所以不合題意返回false。再判斷如果bits大小為1了,那麼返回這個數字是否為0,其實直接返回true也行,因為題目中說了最後一個數字一定是0。然後我們新建一個數組t,如果bits的首元素為0,則我們的t賦值為去掉首元素的bits陣列;如果bits的首元素是1,則我們的t服之為去掉前兩個元素的bits陣列,然後返回呼叫遞迴函式的結果即可,參見程式碼如下:

解法三:

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        if (bits.empty()) return false;
        if (bits.size() == 1) return bits[0] == 0;
        vector<int> t;
        if (bits[0] == 0) {
            t = vector<int>(bits.begin() + 1, bits.end());
        } else if (bits[0] == 1) {
            t = vector<int>(bits.begin() + 2, bits.end());
        }
        return isOneBitCharacter(t);
    }
};

下面這種解法也是用的遞迴,遞迴函式用的不是原函式,這樣可以只用位置變數idx來遍歷,而不用新建陣列t,初始時idx傳入0,在遞迴函式中,如果idx為n了,相當於上面解法中的bits陣列為空了情況,返回false;如果idx為n-1,返回true;如果bits[idx]為0,則返回呼叫遞迴函式的結果,此時idx加上1;如果bits[idx]為1,則返回呼叫遞迴函式的結果,此時idx加上2,參見程式碼如下:

解法四:

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        return helper(bits, 0);
    }
    bool helper(vector<int>& bits, int idx) {
        int n = bits.size();
        if (idx == n) return false;
        if (idx == n - 1) return bits[idx] == 0;
        if (bits[idx] == 0) return helper(bits, idx + 1);
        return helper(bits, idx + 2);
    }
};

類似題目:

參考資料: