1.奇数と偶数を決定します
数値nが2進数として表される場合、最後の2進数が1であるか0であるかを判別するだけで済みます。1の場合は奇数、それ以外の場合は偶数を表します。コードは次のように表示されます。
if(n & 1 == 1){
// n是奇数
}
2.2つの番号を交換します
x = x ^ y; // (1)
y = x ^ y; // (2)
x = x ^ y; // (3)
2つの同一の数の排他的論理和の結果が0、つまりn ^ n = 0であり、0とXORされた後、任意の数がそれ自体に等しいこと、つまりn ^ 0 = nであることは誰もが知っています。
したがって、(1)のxを(2)のxに代入すると、次のようになります。y= x ^ y =(x ^ y)^ y = x ^(y ^ y)= x ^ 0 = x値はに割り当てられますy。
(3)の場合、導出は次のようになります。x= x ^ y =(x ^ y)^ x =(x ^ x)^ y = 0 ^ y = yであるため、yの値はxに割り当てられます。
排他的論理和演算は、可換および結合法則をサポートします。
3.繰り返されていない番号を見つけます
整数データのセットを提供します。これらのデータのうち、1つの数字は1回だけ表示され、他の数字は2回表示されます。数字を見つけましょう
多くの人がハッシュテーブルを使用してこの質問を保存します。保存されるたびに、特定の数の出現回数が記録され、最後にハッシュテーブルがトラバースされて、1回だけ発生する出現回数が検出されます。この方法の時間計算量はO(n)であり、空間計算量もO(n)です。
実際、この問題はビット単位の算術でもあり得ます。すべての整数をXORすることができます。2つの同一の数のXORの結果は0であるため、0の数のXORの結果はそれ自体であるため、排他的論理和の結果ORは、1回だけ表示される番号です。たとえば、このデータセットは1、2、3、4、5、1、2、3、4です。5つは1回だけ表示され、他は2回表示されます。すべてをXORします。結果は次のとおりです。
1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 1 ^ 2 ^ 3 ^ 4 =(1 ^ 1)^(2 ^ 2)^(3 ^ 3)^(4 ^ 4)^ 5 = 0 ^ 0 ^ 0 ^ 0 ^ 5 = 5
コードは次のように表示されます。
int find(int[] nums){
int tmp = nums[0];
for(int i = 1;i < nums.length; i++)
tmp ^= arr[i];
return tmp;
}
4、2のn乗
2のn乗で解き、システムに付属のpow関数を使用できません
この質問を見た多くの人は、n 2を掛けるだけで十分だと思うかもしれません。これを行うと、時間計算量はO(n)になります。では、ビット演算でどのようにそれを行うのでしょうか?
たとえば、n = 13、nの2進数は1101である場合、2の13乗は次のように分解できます。2^ 1101 = 2 ^ 0001 * 2 ^ 0100 * 2 ^ 1000。1101をビットごとに&1と>> 1で読み取ることができます。1の場合、このビットで表される乗数が最終結果に乗算されます。最終的なコードは次のとおりです。
int pow(int n) {
int sum = 1;
int tmp = 2;
while(n != 0) {
if(n & 1 == 1)
sum *= tmp;
temp *= temp;
n >>= 1;
}
return sum;
}
5.N以下の2指数の最大の累乗を見つけます
たとえば、N = 19の場合、バイナリへの変換は00010011です(ここでは便宜上、8ビットのバイナリを使用して表現します)。次に、探している数値は、バイナリの左端の1を保持することであり、後続のすべての1は0になります。つまり、ターゲット番号は00010000です。では、この番号を取得する方法は?対応する解決策は次のとおりです。
1.左端の1を見つけて、右のすべての0を1に変更します
2.取得した値に1を加算すると、00100000、つまり000111111 + 1 = 00100000を取得できます。
3.取得した00100000を1桁右に移動して、00010000を取得します。つまり、00100000 >> 1 = 00010000になります。
だから問題は、最初のステップで左端の1の後に0を取得するにはどうすればよいですか?
コードは次のように表示されます。
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
これは、nを右にシフトしてOR演算を実行することで取得できます。説明させてください。左端の1が2桁のk番目の位置(左から右に数えて)にあり、nを1桁右にシフトした後、k +1番目の位置にあると仮定します。得られた結果も1でなければならず、次にnの結果と右シフトに対してOR演算を実行すると、得られた結果のk番目とk + 1桁は1でなければなりません。同様に、nを右にシフトします。 2ビットで、得られた結果のk桁目+2とk + 3位は1でなければならず、OR演算を再度実行すると、kth、k + 1、k + 2、k +3を取得できます。すべて1であり、以下同様です。
最終的なコードは次のとおりです。
int findN(int n){
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8 // 整型一般是 32 位,上面我是假设 8 位。
return (n + 1) >> 1;
}
このアプローチの時間計算量は約O(1)です。