【LeetCode】338。ビット数

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 2zzzがこの値に等しいのはなぜですか?ここで、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 i1 役割:クリアiiiの最後の1。
だから:iii 1は、数==i&(i − 1)i \&(i-1)i i1 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、ビット操作の基本知識

おすすめ

転載: blog.csdn.net/HeavenDan/article/details/108753304