• 只出现一次的数字


    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    说明:

    你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

    示例 1:

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

    输入: [4,1,2,1,2]
    输出: 4

     

    方法 1:集合操作
    算法

    遍历nums 中的每一个元素
    如果某个nums 中的数字是新出现的,则将它添加到集合中
    如果某个数字已经在集合中,删除它

    #include<iostream>
    #include<set>
    #include<iterator>
    using namespace std;
    set<int>st;
    int main(){
        int num;
        set<int>::iterator it= st.begin();
        while (cin>>num){
            it= st.find(num);
            if(it==st.end())
                st.insert(num);
            else
                st.erase(it);
        }
      for (it = st.begin(); it != st.end(); it++)
            cout << *it << " ";
    }

     关于Set 的STL 知识点:https://www.cnblogs.com/BlairGrowing/p/12709247.html

    复杂度分析

    时间复杂度:O(n2)     我们遍历nums 花费 O(n)的时间。我们还要在列表中遍历判断是否存在这个数字,花费 O(n)的时间,所以总循环时间为 O(n2)
    空间复杂度:O(n) 。我们需要一个大小为 n 的列表保存所有的 nums 中元素。

     

    方法 2:哈希表
    算法

    我们用哈希表避免每次查找元素是否存在需要的 O(n)时间。

    遍历 nums 中的所有元素并建立键/值对。
    返回只出现一次的元素。

     

    int singleNumber(vector<int>& nums) {
            map<int,int> m;
            for(int i=0; i<nums.size();i++){
                if(m.find(nums[i]) != m.end()){
                    m.erase(m.find(nums[i]));
                }else{
                    m[nums[i]] = 1;
                }
            }
            return m.begin()->first;
    }
    int main(){
        int n;
        int arr[] = {4,1,2,1,2};
        vector<int> nums(arr, arr + sizeof(arr) / sizeof(int));
        cout<<singleNumber(nums);
    }

     

    复杂度分析

    时间复杂度:O(n⋅1)=O(n) 。for 循环的时间复杂度是 O(n) 的。Python 中哈希表的 pop 操作时间复杂度为O(1)。
    空间复杂度: O(n) 。hash_table 需要的空间与 nums 中元素个数相等。

     

    方法 3:数学

    概念

    2 * (a + b + c) - (a + a + b + b + c) =c

        set<int>st;
        int sum=0;
        int arr[] = {4,1,2,1,2};
        set<int>::iterator it;
        st.insert(arr,arr+5);
        for (it = st.begin(); it != st.end(); it++)
            sum+=*it;
        sum*=2;
        for (int i = 0; i < 5; i++)
        {
            sum-=arr[i];
        }
        cout<<sum<<endl;

     

    方法 4:按位异或

    按位异或(xor)操作符

      按位操作符的字面意思很好理解,即对值的二进制格式进行处理的操作符。而异或的作用为:假设有值甲、乙,当甲乙值相等时,异或操作后结果为不等(False,0),反之,为相等(True,1)。所以按位异或操作符的释义便显而易见了:对某值的每个位上的值(0或1)进行异或操作。

    举一例例子:

    甲:0 0 0 0 1 1 0 0 (值为12)

    乙:0 0 0 0 0 1 1 1 (值为7)

    甲和乙进行按位异或操作得到新值丙

    丙:0 0 0 0 1 0 1 1 (值为11)

    可见,当两值的某一位的值不同时,按位异或操作后所得新值某一位的值将为 1 (如从右到左第一位),反之为 0 (如从右到左第三位)。

    既然有异或操作符,那么很可能会有同按位的操作符,但我就不再一一介绍了,毕竟我介绍按位异或操作符只是为显得我写的题解内容翔(空)实(洞)。

    逻辑思路

    有了按位异或操作符,我们就可以依照其独特的性质,敲除一段极其华丽的代码。

    但题解是题解,不是我擅长的搬砖,我得先把逻辑思路捋清。

    有一个数组,含有值:12,7,12。并含有一个变量甲,其值为0。(先不要纠结为何要这么定义,这是为了了解按位异或操作符的神奇性质)

    对数组进行遍历,且遍历所得的每个值都和变量甲进行一次按位异或操作。

    ——————第一次:

    12:0 0 0 0 1 1 0 0

    甲:0 0 0 0 0 0 0 0

    异或

    甲:0 0 0 0 1 1 0 0(值为12)

    ——————第二次

    7:0 0 0 0 0 1 1 1

    甲:0 0 0 0 1 1 0 0

    异或

    甲:0 0 0 0 1 0 1 1(值为11)

    ——————第三次

    12:0 0 0 0 1 1 0 0

    甲:0 0 0 0 1 0 1 1

    异或

    甲:0 0 0 0 0 1 1 1(值为7)

    ——————遍历结束
    返回值:甲。甲值为 7 ,数组中唯一元素为 7。

     

    代码:

    int main(){
        int n;
        set<int>st;
        int ans=0;
        int arr[] = {4,1,2,1,2};
        for(int i=0;i<5;i++){
            ans^=arr[i];
        }
        cout<<ans<<endl;
    }

     

    因上求缘,果上努力~~~~ 作者:每天卷学习,转载请注明原文链接:https://www.cnblogs.com/BlairGrowing/p/12773852.html

  • 相关阅读:
    flash player over linux
    chmod 命令
    A*算法
    adb找不到设备
    ubuntu14.04安装wine以及国际版QQ
    linux man
    X-window
    linux file system
    linux command
    directUI
  • 原文地址:https://www.cnblogs.com/BlairGrowing/p/12773852.html
Copyright © 2020-2023  润新知