LeetCode 137. Single Number II 解题报告

LeetCode 137. Single Number II 解题报告

题目描述

Given an array of integers, every element appears three times except for one. Find that single one.


示例

Example 1:
input: [1]
output: 1

Example 2:
input: [2, 2, 3, 2]
output: 3


限制条件

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?


解题思路

我的思路:

首先说明一下这道题的题意,我理解的题意是数组中仅有一个元素出现一次,而其他元素出现了三次。我在官网上测试过了[1, 1, 1, 2, 2]这种仅有一个元素出现不是三次的用例,发现没有结果返回,所以我觉得题意就是说仅有一个元素出现了一次,而不是Discuss里有人认为的仅有一个元素出现次数不足三次。

这道题我没有想出来,最后通过的解法没有符合O(n)的时间复杂度,而是O(nlogn)。
思路就是先排序,然后从头开始遍历,如果某个元素与左右两个都不相同就是单独元素,特殊情况是头尾的情况,分别单独处理即可,因为用到了排序,所以时间复杂度是O(nlogn)

参考思路:

看了Discuss里大神的解法,真是惊叹到无以复加的地步。这里给出一个我理解的解法。
充分利用数组元素是int类型这一特点,统计所有元素的第 i 个bit上为1的个数,因为题目说了其它元素出现了3次,而特殊元素只出现了1次,所以当统计的个数不能整除3就表明特殊元素在第i个bit上是1,所以我们把结果的第 i <script type="math/tex" id="MathJax-Element-215">i</script>个bit设为1,通过检查32个bit,这样我们就构造出了特殊元素,最后返回结果即可,时间复杂度是O(32n)。


代码

我的代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        if (nums.size() == 1)
            return nums[0];

        sort(nums.begin(), nums.end());

        size_t i = 0;

        for (; i < nums.size(); i++) {
            if ((i == 0 && nums[i] != nums[i + 1]) || 
                (i == nums.size() - 1 && nums[i] != nums[i - 1]) ||
                (nums[i] != nums[i - 1] && nums[i] != nums[i + 1]))
                break;
        }

        return nums[i];
    }
};

参考代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int sum = 0;
        int ans = 0;

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

            for (int n: nums) {
                if ((n >> i) & 1)
                    sum++;
            }

            if (sum % 3)
                ans |= 1 << i;
        }

        return ans;
    }
};

总结

这道题我是真的想不出来,真不知道大神们是怎么想的,好佩服。他们的解法适用于数组中仅一个元素出现一次,而其他元素出现n次的情况,条件设为sum % n就行。除了这种解法,Discuss还有其他的解法,不过我没怎么理解就没在这里贴出来了。光是上面贴出来的解法也让我大开了眼界O(∩ _ ∩)O哈哈~。
终于腾出了时间填好这个坑,明天继续,希望能够自己做出来,加油加油~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值