zoukankan      html  css  js  c++  java
  • 剑指offer:数组中只出现一次的数字

    题目描述:

    一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

    思路分析:

    1. 直接想法,每个数字遍历,统计出现次数,复杂度O(n^2),超时。

    2. 借助哈希表,空间换时间,遍历一次,时间复杂度O(n),空间复杂度O(n),对于空间复杂度限制为O(1)时,不满足条件。

    3. 利用异或运算。已知两个相同的数,异或为0。若当前的题目是只求一个只出现一次的数字时,只需要将数组中的数字都异或一次,最后得到的即为所求的只出现一次的数字。那么拓展到两个数字的情况,

    我们可以将原始数组分成两个子数组,使得每个子数组包含一个只出现一次的数字,而其他数字都成对出现。这样,我们就可以用上述方法找到那个孤苦伶仃的元素。

    我们还是从头到尾一次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数组的异或结果。因为其他数字都出现了两次,在异或中全部抵消了。由于两个数字肯定不一样,那么异或的结果肯定不为0,也就是说这个结果数组的二进制表示至少有一个位为1。我们在结果数组中找到第一个为1的位的位置,记为第n位。现在我们以第n位是不是1为标准把元数组中的数字分成两个子数组,第一个子数组中每个数字的第n位都是1,而第二个子数组中每个数字的第n位都是0。

    举例:{2,4,3,6,3,2,5,5}

    我们依次对数组中的每个数字做异或运行之后,得到的结果用二进制表示是0010。异或得到结果中的倒数第二位是1,于是我们根据数字的倒数第二位是不是1分为两个子数组。第一个子数组{2,3,6,3,2}中所有数字的倒数第二位都是1,而第二个子数组{4,5,5}中所有数字的倒数第二位都是0。接下来只要分别两个子数组求异或,就能找到第一个子数组中只出现一次的数字是6,而第二个子数组中只出现一次的数字是4。

    代码:

    思路二:

     1 class Solution {
     2 public:
     3     void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
     4         if(data.size()<=0)
     5             return;
     6         map<int, int> data_map;
     7         for(int i=0; i<data.size(); i++)
     8         {
     9             data_map[data[i]]++;
    10         }
    11         vector<int> v;
    12         for(int i=0; i<data.size(); i++)
    13         {
    14             if(data_map[data[i]]==1)
    15                 v.push_back(data[i]);
    16         }
    17         *num1 = v[0];
    18         *num2 = v[1];
    19     }
    20 };

    思路三:

    class Solution {
    public:
        void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
            int length = data.size();
            if(length<2)
                return;
            //对原始数组求异或
            int resultExclusiveOR = 0;
            for(int i=0; i<length; i++)
                resultExclusiveOR ^= data[i];
            
            unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);
            *num1 = 0;
            *num2 = 0;
            for(int j=0; j<length; j++)
            {
                if(IsBit1(data[j], indexOf1))
                {
                    *num1 ^= data[j];
                }
                else
                {
                    *num2 ^= data[j];
                }
            }
        }
    private:
        //找到二进制数num第一个为1的位数,如0010,第一个为1的位数是2
        unsigned int FindFirstBitIs1(int num)
        {
            unsigned int indexBit = 0;
            //只判断一个字节的
            while((num & 1)==0 && (indexBit < 8*sizeof(unsigned int)))
            {
                num = num >> 1;
                indexBit++;
            }
            return indexBit;
        }
        //判断第indexBit位是否为1
        bool IsBit1(int num, unsigned int indexBit)
        {
            num = num >> indexBit;
            return (num & 1);
        }
    };
  • 相关阅读:
    Python网络协议(osi七层协议)
    Python面向对象之反射,双下方法
    Python类的成员
    Python异常处理
    mysql 索引 慢查询优化 && 数据库性能优化
    数据库(视图、事务、存储过程、函数) && 数据库备份
    mysql数据库连接模块 pymysql && sql注入
    主线程与子线程的关系
    socket 编程实例 基于线程池实现服务端并发
    日常迷惑积累
  • 原文地址:https://www.cnblogs.com/LJ-LJ/p/10960291.html
Copyright © 2011-2022 走看看