剣とは、offer56の質問の軽さと、さまざまな理解またはより深い理解の配列に含まれる数字の数を指します(2つの異なる数字があります)

剣とは、offer56の質問の軽さと、さまざまな理解またはより深い理解の配列に含まれる数字の数を指します(2つの異なる数字があります)

前任者

配列内の数の出現回数についても同じですが、異なる数は1つだけです。この問題には多くの解決策があり、2つの配列を作成するか、ポインターやその他の方法を使用してそれを行うことができますが、時間はこれらの方法の複雑さは理想的ではありません。このとき、排他的論理和の役割を果たす必要があります。このビット演算子の場合、最初に使用するのは2つの数値を交換するときです(3番目の変数を使用せず、intの範囲内にあることを確認する必要があります)。このメソッドの後、2番目を直接呼び出します。この問題に対して、XORは再びその魔法の効果を発揮しました。

#include<stdio.h>
int main()
{
    
    
   int a = 2;
   int b = 3;
   a = a^b;
   b = a^b;
   a = a^b;
   printf("%d%d", a, b);    //此时只需3次异或,就可以交换两个数,而且不用借助第3个变量,同时也可以保证在int的范围内
}  

この問題の前身として、XOR演算を使用することもできます。配列内のすべての要素をXORして異なる数を見つけますが、現時点では重要な前提があります。つまり、これらの繰り返される数は偶数を繰り返す必要があります。なぜなら、それが偶数回繰り返され、次にその異なる数とXORされた場合にのみ、結果はその異なる数になる可能性があるからです。これ
は逆です。

#include<stdio.h>
int main()
{
    
    
	int a[4] = {
    
     1, 1, 1, 4 };
	printf("%d", a[0] ^ a[1] ^ a[2] ^ a[3]);
}

ここに画像の説明を挿入

この時点で、繰り返される数は偶数回ではなく奇数回繰り返されるため、結果は希望どおりではないことがわかります。

このとき、ソードフィンガーオファー56の質問を見ると、詳細がわかります。その例では、繰り返される数字はすべて偶数回表示されます。これは偶然ではありませんが、避けられません。

この問題の前身を理解すると、前任者の解決策の助けを借りてこの問題を解決できるかどうかを考えるのは難しいことではありませんが、配列内のすべての要素をXORすると、それが私たちが望むものではないことがわかりますはい、これがこの質問の難しさです。ここで類推を学ぶ必要があります。この問題を単に「以前に問題があったか」に変えるのではなく、これら2つの異なる数値を分離してXORする方法を考えられますか。

実装コード

#define RESULT_LEN 2
int* singleNumbers(int* nums, int numsSize, int* returnSize)
{
    
    
       int *ret = (int *)malloc(RESULT_LEN * sizeof(int));
       memset(ret, 0, RESULT_LEN * sizeof(int));
       int s=0;
       int i=0;
       for(i=0;i<numsSize;i++)
       {
    
    
          s^=nums[i];
       }
       int k=1;
       while(k<=s)
       {
    
    
           if((s&k)!=0)
           {
    
    
               break;
           }
           k<<=1;
       }
       for(i=0;i<numsSize;i++)
       {
    
    
           if((nums[i]&k)==0)
           {
    
    
              ret[0]^=nums[i];
           }
       }
       ret[1]=s^ret[0];
       *returnSize=RESULT_LEN;
       return ret; 
}

コードの各部分に関する簡単な説明

     for(i=0;i<numsSize;i++)  
       {
    
    
          s^=nums[i];
       }

配列内のすべての要素をXORすることは、2つの異なる数をXORすることと同じです。これは、同じ数が偶数回しか表示されないためです。この手順は、主に、次の除算に備えるための識別基準を見つけることです。2つの異なる数を分離するには、それらを分離するための基準がなければなりません
。2。

     int k=1;        
       while(k<=s)
       {
    
    
           if((s&k)!=0)
           {
    
    
               break;
           }
           k<<=1;
       }

このとき、得られた結果はAND演算にかけられます。目的は、1である最初の桁を見つけ、このビットを区別の基準として使用して、配列を2つに分割することです。これにより、2つの異なる番号を別々に分離できます。最初の桁が1であることを確認する目的は、対応する桁が1である番号をグループにグループ化し、1以外の番号をグループにグループ化することです
。3 。

 for(i=0;i<numsSize;i++)  
       {
    
    
           if((nums[i]&k)==0)
           {
    
    
              ret[0]^=nums[i];
           }
       }

現時点では、この問題の前身になっているので、探している番号を個別にXORすることで取得できます。ここでは、見つける必要があるだけなので、対応する位置に1があるすべての番号をXORしませんでした。異なる数。、排他的論理和のプロパティを使用できます。または、見つかった数が最初の2桁のXORの結果とXORされている限り、残りの異なる数を見つけることができます。残りの数を取得できます。コードは次のとおりです。

ret[1]=s^ret[0]; 

排他的
論理和に関しては、次のプロパティがあります。可換法則:A ^ B = B ^ A;
結合法則:A ^(B ^ C)=(A ^ B)^ C;
アイデンティティ法則:X ^ 0 = X;
returnゼロ法則:X ^ X = 0;
反射:A ^ B ^ B = A ^ 0 = A;
任意のXの場合:X ^(-1)= 〜X;
A ^ B = Cが成り立つ場合、A ^ B = C、B ^ C = A

まとめ(実はずっと前に会った)

実際、排他的論理和演算は、振り返ってみると、私たちのほとんどが実際に高校で接触していました。数学では、排他的論理和演算は⊕と書かれています。これには次の特性があります。

  1. a⊕a= 0
  2. a⊕b=b⊕a
  3. a⊕b⊕c=a⊕(b⊕c)=(a⊕b)⊕c;
  4. d =a⊕b⊕c、a =d⊕b⊕cを推定できます。
  5. a⊕b⊕a= b。

この記号⊕私たちは実際に高校で数学と接触しました。常にいくつかのデータの問題があります。つまり、定義の問題でこの記号が発生します。これは、実際には、高校の知識は、大学の基礎を敷設されており、大学のいくつかの知識は、対象の高校に出てくる、また良い証拠である、おそらくこれは、強い置く人たちの疑問がある。
ことでこの質問については、XORについても深く理解しています。最初は、XORの使用法に基づいて理解していました。同じビットは0で、異なるビットは1です。後で2つの番号を交換すると、いくつかの問題が発生します。実際、XORはバイナリシステムでの加算と減算です。今では理解が深まり、多くの特性
理解し、区別の基準として利用できるようになりました。深く学ぶことで、XORについても深く理解できると思います。これまでのところ、つまり、 Jianzhiオファー56とXORの軽さを表面的に理解している。

おすすめ

転載: blog.csdn.net/IamGreeHand/article/details/115280663