LeetCode 137. 只出现一次的数字 II (逐位考虑+位运算)

54 篇文章 0 订阅

1.题目

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

说明:

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

示例 1:

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

输入: [0,1,0,1,0,1,99]
输出: 99

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.题解

逐位考虑

不考虑出现次数为一的数字,其他所有出现次数3的数字加和,分别对每一位做模3运算,得到的一定都是零,再加上那个出现次数唯一的数字对应位的值即可。(通用,对出现次数为n同样适用。)

class Solution
{
public:
    int singleNumber(vector<int>& nums)
    {
        int res = 0;
        for (int i = 0; i < 32; ++i)
        {
            int cnt = 0;
            for (auto x : nums)
            {
                cnt += (x>>i)&1;
            }
            res |= (cnt%3)<<i;
        }
        return res;
    }
};

位运算

我们还可以用自动机来做这题,根据某一位 1 的个数,我们可以得到如下的状态自动机:
在这里插入图片描述
初始的时候在状态 0 (有 0 个 1),然后如果下一个数这一位是 1,就进入状态 1(有 1 个 1),接着如果下一个数这一位是 1,就进入状态 2(有 2 个 1),接着如果下一个数这一位是 1,就进入状态 3(有 3 个 1),最后如果再来了一个数这一位还是 1,就说明是一个新的数了,等价于回到了状态 1。而每个状态如果来的数这一位是 0 ,都会保持状态不变。

当然这个自动机还可以简化,注意观察可以发现状态 3 和状态 0 是等价的(输入 0 都保持不变,输入 1 都会进入状态 1)。所以我们将状态 1 和状态 3 合并为一个状态 0 ,得到如下的状态自动机:

在这里插入图片描述
因为一共有三个状态,所以我们需要用两个变量来表示状态。用 once 表示是否在状态 1,用 twice 来表示是否在状态 2 。那么两个变量都为 0 就表示在状态 0 。然后可以得到如下的状态转移表:

在这里插入图片描述
在这里插入图片描述

class Solution
{
public:
    int singleNumber(vector<int>& nums)
    {
        int once = 0, twice = 0;
        for (auto x : nums)
        {
            once = (once^x)&(~twice);
            twice = (twice^x)&(~once);
        }
        return once;
    }
};

链接:https://leetcode-cn.com/problems/single-number-ii/solution/zi-dong-ji-wei-yun-suan-zui-xiang-xi-de-tui-dao-gu/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值