1.タイトル
負でない整数numが与えられます。0≤i≤numの範囲の各桁iについて、その2進数の1の数を数え、それらを配列として返します。
例1:
输入: 2
输出: [0,1,1]
例2:
输入: 5
输出: [0,1,1,2,1,2]
上級:
- O(n * sizeof(integer))の時間の複雑さを持つソリューションを与えることは非常に簡単です。しかし、線形時間O(n)で1回のスキャンでそれを行うことができますか?
- 必要なアルゴリズムのスペースの複雑さはO(n)です。
- ソリューションをさらに洗練できますか?この操作を実行するには、組み込み関数(C ++の__builtin_popcountなど)をC ++またはその他の言語で使用しないでください。
二、解く
1.暴力
アイデア:
任意の数x(0 <= x <= num)でビット計算を実行します。ここでライブラリ関数を直接呼び出します。もちろん、自分で作成することもできます。
コード:
class Solution {
public int[] countBits(int num) {
int[] cnt = new int[num+1];
for (int i=0; i<=num; i++) {
cnt[i] = Integer.bitCount(i);
}
return cnt;
}
}
時間の複雑さ: O(n)O(n)O (n )、bitCount()は5回の操作で取得でき、ソースコードは次のようになります。191。ビット1の
スペースの複雑さの数: O(n)O(n)O (n )
2.全体的なシフト
アイデア:
任意の数iの場合、そのバイナリ表現は1の数cntであり、次のような関係があります:cnt(i)= cnt(i / 2)+ i%2。
簡単な理解の下で:
x = = 2 y + 0 x == 2y +0の場合バツ==2 Y+0、则cnt(x)= = cnt(y)cnt(x)== cnt(y)c n t (x )==c n t (y );
若x = = 2 y + zx == 2y + zバツ==2 Y+z、则cnt(x)= = cnt(y)+ cnt(z)cnt(x)== cnt(y)+ cnt(z)c n t (x )==c n t (y )+c n t (z )。
ここで、z = x%2 z = x \%2と=x %2、zzzがこの値に等しいのはなぜですか?ここで、yをバイナリに入れ、次にxxを入れます。x正しいyyyは全体として左にシフトされ、最後にzzになります。z、2つの可能性、0または1、xx%2を使用xはそれを意味します。次に、検証と理解のために、番号、バイナリ表現、および1の数を以下にリストします。
x 二进制 1个数
0 0 0
1 1 1
2 10 1
3 11 2
4 100 1
5 101 2
6 110 2
7 111 3
8 1000 1
9 1001 2
10 1010 2
11 1011 3
12 1100 2
13 1101 3
14 1110 3
15 1111 4
16 10000 1
コード:バージョン1。
class Solution {
public int[] countBits(int num) {
int[] cnt= new int[num+1];
for (int i=0; i<=num; i++) {
cnt[i] = cnt[i/2] + i%2;
}
return cnt;
}
}
コード:バージョン2、ビット操作に置き換えられました。これは操作が高速になる可能性があります。
class Solution {
public int[] countBits(int num) {
int[] cnt= new int[num+1];
for (int i=0; i<=num; i++) {
cnt[i] = cnt[i>>1] + (i&1);
}
return cnt;
}
}
時間の複雑さ: O(n)O(n)O (n )
スペースの複雑さ: O(n)O(n)O (n )
3.ビット操作
アイデア:
因是:i&(i − 1)i \&(i-1)i &(i−1 )役割:クリアiiiの最後の1。
だから:iii 1は、数==i&(i − 1)i \&(i-1)i &(i−1 ) 1 +1の数
コード:
class Solution {
public int[] countBits(int num) {
int[] cnt= new int[num+1];
for (int i=1; i<=num; i++) {
cnt[i] = cnt[i&(i-1)] + 1;
}
return cnt;
}
}
時間の複雑さ: O(n)O(n)O (n )
スペースの複雑さ: O(n)O(n)O (n )
4.動的計画
アイデア:
以下のように分析します。
Index : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
num of 1: 0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4
由上得出:
dp[0] = 0;
dp[1] = dp[0] + 1;
dp[2] = dp[0] + 1;
dp[3] = dp[1] +1;
dp[4] = dp[0] + 1;
dp[5] = dp[1] + 1;
dp[6] = dp[2] + 1;
dp[7] = dp[3] + 1;
dp[8] = dp[0] + 1;
dp[1] = dp[1-1] + 1;
dp[2] = dp[2-2] + 1;
dp[3] = dp[3-2] +1;
dp[4] = dp[4-4] + 1;
dp[5] = dp[5-4] + 1;
dp[6] = dp[6-4] + 1;
dp[7] = dp[7-4] + 1;
dp[8] = dp[8-8] + 1;
dp[index] = dp[index - offset] + 1;
ねえ、内部の独立変数オフセットも変化しているので、法則を要約するのは実際には難しいです。後で手がかりとしてそれを研究しましょう。
コード:
public int[] countBits(int num) {
int result[] = new int[num + 1];
int offset = 1;
for (int index = 1; index < num + 1; ++index){
if (offset * 2 == index){
offset *= 2;
}
result[index] = result[index - offset] + 1;
}
return result;
}
時間の複雑さ: O(n)O(n)O (n )
スペースの複雑さ: O(n)O(n)O (n )
3、参照
1. 3行のJavaソリューション
2.私たちはインタビューでこの質問を扱う方法[思考プロセス+ DPソリューション]
3.理解容易DP&ビットのJavaソリューション
4、Javaの再帰はO(n)時間O(1)余分なスペースが4msの
5。ビットカウント
6、ビット操作の基本知識