LeetCode —— 137. 只出现一次的数字 II

在这里插入图片描述

‍️‍️‍️‍️Take your time ! ‍️‍️‍️‍️
个人主页:大魔王
所属专栏:魔王的修炼之路–C++
如果你觉得这篇文章对你有帮助,请在文章结尾处留下你的点赞关注,支持一下博主。同时记得收藏✨这篇文章,方便以后重新阅读。

137. 只出现一次的数字 II

这个题在力扣是中等标签,虽然不等于它很难, 但他绝对不简单,比如这个题虽然单纯做题是很简单,但是规定了时间和空间复杂度,那么就难了起来。

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。
示例 1:
输入:nums = [2,2,3,2]
输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,99]
输出:99
提示:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次

下面是错误的写法,没有考虑时间和空间复杂度。

// // //复杂度不行 可能是因为递归层次太深,递归每次都会在栈开空间,最会情况就是开n次
// class Solution {
// public:
//     int singleNumber(vector& nums) {
//         sort(nums.begin(), nums.end());
//         int i = 0;
//         if(nums[0] != nums[1])
//             return nums[0];
//         i += 3;
//         while(i < nums.size() - 1)
//         {   
//             if(nums[i] != nums[i + 1])
//                 return nums[i];
//             i += 3;
//         }
//         return nums.back();
//     }
// };

首先sort排序使用的快排,快排一般情况下时间复杂度是NlogN,最坏的话就是 N^2,就这个一般情况来说,NlogN是对数线性复杂度,他介于线性和二次方之间,线性一般指的是O(N)这样子的;对于它的空间复杂度也是不满足的,因为递归造成的空间复杂度也是算的,不过可能实现的快排不是递归,而且库里的sort底层实现也可能不只快排而是几中排序的结合优化版,不过时间复杂度通常就是O(N*logN),至于空间复杂度,O(logN),就和一般情况下的快排一样,递归实现的快排而且是最坏情况的话,那么就是O(N)了。

正确解法

//分别将这些数对应二进制位的1有几个存到整型数组p中,然后分别 % 3,是3的倍数的就没了
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        size_t arr[32] = {0};
        size_t a = 1;
        int flag = 0;
        int special = 0;
        for(auto x: nums)//存1
        {
            if(x < 0)
            {
                if(x == -2147483648)//这样也不行,因为这个形参里面的类型int,最小的负数转为正数就越界了,比如char,最大 127,最小-128
                {
                    x += 1;
                    special++;
                }
                x *= -1;//负数变成补码就反了一下,不适合了。   
                flag++;

            }
            for(int i = 0; i < 32; i++)
            {

                if(((a << i) & x) != 0)
                {

                    arr[i]++;
                }
            }
        }

        int num = 0;
        int system = 31;
        for(int i = 0; i < 32; i++)
        {
            if(i == 31)
            {
                cout  << "进来了" << endl;
                arr[i] %= 3;
            }
            if(arr[i] % 3 != 0)
            {
                num += pow(2, i); 
            }
        }
        if(flag % 3 != 0)
            num *= -1;
        if(special == 1)
            num--;
        return num;

    }
};

这里面最有价值的是里面没有通过排序,然后找单独数字就是直接开辟一个常量级(32个int)的空间,通过记录这些数二进制位的总位数,然后判断哪个 % 3 不等0,那么该数就是单独的。
有个小问题,如果是负数的话,那么在内存中就是补码,上面写的代码就不适合了,但是数据中可能有负数,所以只能将负数改为正数,这是不影响的,但是有一点,负数最大数的绝对值比正数大1,因为就像char,最大127,最小-128,所以转的时候就爆了,超出int范围。
当然这只是自己的解法,所以有个这个坑,要特殊处理一下,肯定有比这好的方法,但是自己真想不出来了,也不想看题解。

  • 博主长期更新,博主的目标是不断提升阅读体验和内容质量,如果你喜欢博主的文章,请点个赞或者关注博主支持一波,我会更加努力的为你呈现精彩的内容。

专栏推荐
魔王的修炼之路–C语言
魔王的修炼之路–数据结构初阶
魔王的修炼之路–C++
魔王的修炼之路–Linux
更新不易,希望得到友友的三连支持一波。收藏这篇文章,意味着你将永久拥有它,无论何时何地,都可以立即找到重新阅读;关注博主,意味着无论何时何地,博主将永久和你一起学习进步,为你带来有价值的内容。

你可能感兴趣的:(力扣题目汇总,leetcode,算法,职场和发展,c++,数据结构)