剣はオファーを参照します (C++)-JZ56: 配列内で 1 回だけ出現する 2 つの数値 (アルゴリズム ビット演算)

著者: Zhai Tianbao Steven
著作権表示: 著作権は著者に属します。商業的転載の場合は、許可について著者に連絡してください。非商業的な転載の場合は、出典を示してください。

タイトル説明:

整数配列では、1 回しか出現しない 2 つの数値を除き、他のすべての数値は 2 回出現します。一度しか出現しないこれら 2 つの数字を見つけるプログラムを作成してください。

データ範囲:配列の長さ 2≤n≤1000、配列内の各数値のサイズ 0<val≤1000000
要件:空間計算量 O(1)、時間計算量 O(n)

ヒント: 出力時に非降順で並べ替えます。

例:

入力:

[1,4,1,6]

戻り値:

[4,6]

例証します:

小さい方の数値を最初に返します   

問題解決のアイデア:

この問題はビット演算について調べます。問題を解決する 2 つの方法。

1) 暴力の法則

       ハッシュ テーブルを使用して出現頻度を記録し、頻度 1 の数値を出力します。この方法の空間の複雑さは、タイトルの要件を満たしていません。

2) XOR演算

       XOR 演算は、2 つの数値が 0 に等しく、1 とは異なることを意味します。探している数字以外は 1 回出現し、他の数字は 2 回出現するため、これらの数値を XOR した後、その性質に応じて重複する数値を相殺し、1 回出現した数値のみを保持します。

       4^1^2^1^2 など。4 は 100、1 は 001、2 は 010、4^1 は 101、^2 は 111、^1 は 110、^2 は 100 になります。は4です。

       2 つの数値が 1 回出現する場合、結果はこれら 2 つの数値の XOR と等価になります。たとえば、4^1^2^1^2^3 の場合、最終結果は 111、つまり 4^3 になります。

       このトピックでは、これら 2 つの数値を出力する必要があるため、111 をどのように分離するか? 4 と 3 で、特定のビットが同じでない場合、XOR 結果のビットは 1 になります。t を 001 から定義し、t を 111 で演算して、最初に 1 になるビット (111 の右端) を見つけます。は 1 で、00x の位置で数値 4 と数値 3 が異なることを示します。再度トラバースして、このビットの数値に従ってすべてのデータを分類すると、2 つのグループが得られます。数値 1 のグループは次のとおりです。 3、および番号 0 のグループ。グループの結果は 4 です。

       このトピックは、このソリューションに合わせて作成されたものであると言わざるを得ません。各条件は完全に一致します

テストコード:

1) 暴力の法則

class Solution {
public:
    // 寻找出现一次的数字
    vector<int> FindNumsAppearOnce(vector<int>& nums) {
        unordered_map<int,int> um;
        vector<int> result;
        // 遍历数组
        int size = int(nums.size());
        for(int i = 0; i < size; ++i){
            um[nums[i]]++;
        }
        // 寻找出现频率为1的数
        for(int i = 0; i < size; ++i){
   
   {
            if(um[nums[i]] == 1){
                result.emplace_back(nums[i]);
            }
        }}
        // 按大小顺序输出
        if(result[0] < result[1]){
            return result;
        }
        else{
            return { result[1], result[0] };
        }
    }
};

2) XOR演算

class Solution {
public:
    // 寻找出现一次的数字
    vector<int> FindNumsAppearOnce(vector<int>& nums) {
        vector<int> result{ 0, 0};
        // 遍历数组进行异或运算
        int temp = 0;
        int size = int(nums.size());
        for(int i = 0; i < size; ++i){
            temp ^= nums[i];
        }
        // 找到两个数不相同的第一位
        int t = 1;
        while((t & temp) == 0){
            t <<= 1;
        }
        // 再次遍历,将t位为1的数归为1组,为0的数归为1组,这样两组的异或运算得到的结果就是两个不重复数
        for(int i = 0; i < size; ++i){
            if((t & nums[i]) == 0){
                result[0] ^= nums[i];
            }
            else{
                result[1] ^= nums[i];
            }
        }
        // 按大小顺序输出
        if(result[0] < result[1]){
            return result;
        }
        else{
            return { result[1], result[0] };
        }
    }
};

おすすめ

転載: blog.csdn.net/zhaitianbao/article/details/132278174