【每日刷题】只出现一次的数字 III

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sd4567855/article/details/86351064

day17, 只出现一次的数字 III

题目来源:leetcode
给定一个整数数组nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。找出只出现一次的那两个元素。

示例 :
输入: [1,2,1,3,2,5]
输出: [3,5]

注意:
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

解答:首先介绍一下非常数空间复杂度的方法, 开辟一个set容器,遍历数组nums, 如果遇到的某一个元素不在set中,则将该元素插入到set中,如果遇到的某一个元素在set中,则删除set中的该元素。最后将set中元素复制到一个vector中即可。运行时间O(n), 空间复杂度O(n).
当然,有先排序后遍历的,时间复杂度超过了线性,这里不再介绍。

代码:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        set<int> record;
        for( int i = 0; i < nums.size(); i++){
            if( record.find( nums[i]) != record.end())
                record.erase( nums[i]);
            else
                record.insert( nums[i]);
        }
        vector<int> result;
        for( set<int>::iterator it = record.begin(); it!=record.end(); it++)
            result.push_back( *it);
        
        return result;
    }
};

运行结果:image.png-23.4kB

解法2:介绍一种线性时间、常数空间的解法。由于题目要求,只有两个元素出现一次,剩下全部元素均出现两次。对于数组中全部元素进行异或,出现两次的元素经过异或之后为0,两个只出现一次的元素经过异或后的数值设为compare。我们接下来的目的是用comapre将两个元素分离出来。
如何分离? 假设两个只出现一次的元素为 5和3,那么compare = 110, 从compare中选择任意等于1的一位,同时将其他位置全部置为0,例如选择100,或者010。这里选择010,之后010与数组全部元素进行相与操作,若相与结果为0,则划分到数组一,若相与结果不为0,则划分到数组二。
之后数组一内的元素全部异或,数组二内的全部元素异或,即可得到答案。

代码:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int compare = 0;
        vector<int> result;
        result.push_back(0);
        result.push_back(0);
        
        for( int i = 0; i < nums.size(); i++)
            compare ^= nums[i];
        
        compare = compare & ( ~(compare - 1));
        
        for( int i = 0; i < nums.size(); i++)
            if( (compare & nums[i]) == 0) //注意(compare & nums[i]) 要加括号,否则运算顺序不正确
                result[0] ^=nums[i];
            else
                result[1] ^=nums[i];
        
        return result;
    }
};

运行结果:emmm… 为什么运行时间一样。。。
image.png-22.6kB


我的微信公众号

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/sd4567855/article/details/86351064