数组中只出现一次的数字

一、数组中只出现一次的两个数字

题目描述

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

思路分析

在这里插入图片描述

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        vector<int> v;
        // step 1 : 计算两个只出现一次的数的异或值
        int tmp = 0;
        for (auto num : nums) {
            tmp ^=  num; // 任何数和零异或都等于其本身
        }
        
        // step 2 : 找到tmp中任意一个为1的位
        unsigned int flag = 1;
        while ((tmp & flag) == 0) { // 初始值:tmp最后一位为1
           flag = flag << 1;
        }

        // step3: 按照flag分组
        int res1 = 0;
        int res2 = 0;
        for (auto num : nums) {
            if (num & flag) {
                res1 ^= num;
            } else {
                res2 ^= num;
            }
        }
        return vector<int> {res1, res2}; // 注意这种写法
    }
};

注意:

  • == 的优先级比&高
  • return vector的写法

二、数组中唯一只出现一次的数字

题目描述

面试题56-2:在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

思路分析

(1)最优解法,时间复杂度o(n),空间复杂度o(1)

我们想一下如果一个数字出现三次,那么他的二进制位表示的每一位(0或1)也出现了三次.如果把所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位的和都能被3整除

我们把所有数字的二进制位的每一位加起来.若果某一位的和能被3整除,那么那个只出现一次的数字二进制表示中对应的那一位为0,否则为1

步骤:

统计所有数字二进制位的和
判断每一位的和能否被3整除,求解最后结果
时间复杂度O(n),空间复杂度O(1)(常数空间))

//位运算,统计二进制每一位1出现的次数,每一位%3后结果就是这个数
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        // 使用常数量空间,存储每一位1的个数
        int bits[32] = {0};
       
        //从数组低位到高位存储相应位1的次数
        unsigned int flag = 1;  //判断当前位是否为1,lecoode中当flag为int时,无法通过测试
        for(int i=0; i<32; i++){
            for(int j=0; j<nums.size();j++){
                // 判断语句很重要,因为&的结果不一定为1,0100
                if(nums[j] & flag)
                    bits[i] = bits[i]+1;
            }
            flag = flag<<1;
        }
        
        // 从高位到低位读取
        int result = 0;
        for(int i=31; i>=0; i--){
            result = (result<<1);	//和下面的一个语句不可以交换顺序
            result += (bits[i] % 3);    //bits[i] % 3 要么为0要么为1
        }

        return result;
    }
};
  • 对unsigned int进行移位操作时,最高位不会有任何特殊性。
  • 对int进行移位操作时,必须考虑最高位,向右移位操作相当于 (有符号数值)/2。

20240420

class Solution {
public:
    // 统计所有数字的各二进制位中 1的出现次数,并对3求余,结果则为只出现一次的数字
    int singleNumber(vector<int>& nums) {
        // step 1 :求所有数各二进制位的和
		vector<int> bits(32, 0);
        for (auto num : nums) {
            int i = 0;
            unsigned int mask = 1;
            for (; i < 32; i++) {
                if ((num & mask) == mask) {
                    bits[i]++;
                }
                mask = mask << 1;
            }
        }verse(bits.begin(), bits.end()); // 将二进制位正常顺序布置
        // step 2 : 各位对3求余,结果为只出现一次的数字
        unsigned int res = 0;
        for (auto bit : bits) {
            res = res << 1;
            res |= bit % 3; // 要么等于0,要么等于1
            
        }
    return res;
    }
};

(2)哈希表解法,时间和空间复杂度均为o(n)

首先遍历一次数组,将每个数字出现的次数存储到哈希表中
查找哈希表中仅出现一次的数字
时间复杂度O(n),空间复杂度O(n)

class  Solution{
public:
    int singleNumber(vector<int>& nums){
        int length = nums.size();
        //if(!length)  return 0;
       
        map<int, int> hash;
        for(int i = 0; i < length; ++i)
            ++hash[nums[i]];

        for(int i = 0; i < length; ++i)
            if(hash[nums[i]] == 1)
                return nums[i];
        return -1;  //没有出现一次的,或者输入的空数组
    }
};
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> mp;
        for (auto num : nums) {
            ++mp[num];
        }
        unordered_map<int, int>::iterator iter = mp.begin();
        for (; iter != mp.end(); iter++) {
            if (iter->second == 1) {
                break;
            }
        }
        return iter->first;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值