LeetCode 137. Single Number II 解题报告

本文解析了LeetCode 137题Single Number II的解题思路及实现方法。针对数组中只有一个元素出现一次而其余元素均出现三次的问题,介绍了排序后遍历查找的O(nlogn)复杂度解法,并分享了一种统计每个比特位1的个数来确定目标元素的O(32n)复杂度高效解法。

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个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
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值