Try   HackMD

【LeetCode】 338. Counting Bits

Description

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.

Follow up:

  • It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
  • Space complexity should be O(n).
  • Can you do it like a boss? Do it without using any builtin function like builtin_popcount in c++ or in any other language.

給予一非負整數num。對每個符合0 ≤ i ≤ num的數字i,去計算它的二進制表示法中有多少個1並用陣列回傳答案。

進階:

  • 這很容易就能找到一個答案是在執行時間 O(n*sizeof(integer)) 中。但你可以完成在線性時間 O(n) 並在一次掃描(pass這邊翻掃描,不知道怎麼翻比較好XD 反正就是只跑一輪陣列)中完成嗎?
  • 空間複雜度應該在O(n)
  • 你可以像個boss一樣地完成嗎?不使用任何內建的函式庫,例如C++中的 builtin_popcount 或是其他語言中任何相似的東西來完成該題。

Example:

Example 1:

Input: 2
Output: [0,1,1]


Example 2:

Input: 5
Output: [0,1,1,2,1,2]

Solution

  • 其實不太確定進階題指的是什麼,但我覺得我的解法挺快的應該沒問題吧?
  • 首先,我們想想看二進制有什麼規律,以下是0 ~ 7的二進制轉換:
Base 10 Base 2
0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
  • 這邊我刻意使用靠右對齊,你有看出什麼嗎?
    • 沒錯,最小位元的部分都是前面出現過的!
  • 什麼意思?你可以發現2 ~ 30 ~ 1 最前面加上14 ~ 70 ~ 3最前面加上1
  • 也就是說,我們可以用2的平方去當作切割點,後面的都是前面的值+1。我們只要先初始化最前面的值,後面的都可以用前面算出來。
  • 知道規則之後就是用迴圈去判斷每個點要去抓前面的哪個點再加一放進去,詳細就參照下面的code吧。
  • 順帶一提,下面雖然有兩層for,但內層受到外層控制,整個最多只會跑num次,因此壓在O(n)的時間複雜度中。

Code

class Solution { public: vector<int> countBits(int num) { vector<int> v(num + 1, 0); if(num == 0) return v; v[1] = 1; if(num == 1) return v; for(int logCount = 1; pow(2, logCount) - 1 < num; logCount++) { int s = pow(2, logCount); for(int i = s; i <= num && i < pow(2, logCount + 1); i++) { int temp = v[i - s]; v[i] = temp + 1; } } return v; } };
tags: LeetCode C++