zoukankan      html  css  js  c++  java
  • Leetcode 137 Single Number II 仅出现一次的数字

    原题地址
    https://leetcode.com/problems/single-number-ii/

    题目描述
    Given an array of integers, every element appears three times except for one. Find that single one.
    给出一个整数数组,除了某个元素外所有元素都出现三次。找出仅出现一次的数字。

    Note:
    注意:

    Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
    你的算法需要在线性时间复杂度内运行。你可以在常数空间复杂度内实现吗?要求:时间复杂度O(n),空间复杂度O(1)。

    Tags Bit Manipulation

    解题思路
    Single Number系列的第二题,第一题请看 Leetcode 136 Single Number 仅出现一次的数字 。

    实际上136题是137题都是一个特例,更抽象的题目是,有一个数组,其中有一个元素出现了x次,其余所有元素都出现了y次(x < y),找出这个出现了x次的元素。关于这个问题,我们在另一篇文章里进行讨论(请看Leetcode Single Number 扩展)。这里我们只讨论137这个题目。

    由于除去目标元素target之外,所有元素都出现3次,假设出现3次的元素有n个,这样的话假如我们统计所有元素的某一位(比如最后一位),其一共有3n+1个二进制位。因为对与同一个元素来说,其所有的二进制位一定是相同的,所以对这些元素的某一位来说一定是以3个1或3个0为单位出现的,即3n+1个二进制位中一定是3x个1和3y个0,其中x+y=n,再外加一个target对应的二进制位(1或0都有可能)。综上所述,我们可以统计所有数字每一位上1的个数,对3取模,如果为1就说明target对应位为1,否则为0。

    下面问题就是如何统计每一位上1的个数,一个比较好的方法就是采用位运算来处理,当个数满3时就清零(当然这是参考的网上大神们的思路)。

    我们用三个整数one,two, three的二进制位来分别表示32位整数某一位上1出现次数是否为1次、2次、3次,举例,假如:

    one = 1 --- 0x00000001 --- 00000000 00000000 00000000 00000001
    则表示当前统计情况下最低位出现1的次数为1次
    two = 3 --- 0x00000003 --- 00000000 00000000 00000000 00000011
    则表示当前统计情况下最低位出现1的次数为2次,倒数第二位出现1的次数为2次
    three = 4 --- 0x00000004 --- 00000000 00000000 00000000 00000100
    则表示当前统计情况下最倒数第三位出现1的次数为3次

    大神们说one two three可以称之为掩码。

    有了如上逻辑后,我们可以遍历所有的数字,对于每个数字,操作其所有的二进制位,来更新one two three三个数字。当我们遍历完所有数字时,由于除去target只出现一次外,其余元素都是以3为单位出现的,所以可以知道one中存储的二进制位代表的数字就是target。

    对于实际代码中,one two three三者的更新,有以下两个版本,版本一是我自己想出来的,更通用,而且更接近于上面提出的更一般的问题的解决思路(代码一);版本二是网上大神们的代码,只能说更巧妙一些,但是实际上都一样(代码二)。详细请看代码部分中的注释。

    以下来自牛客:https://www.nowcoder.com/questionTerminal/1097ca585245418ea2efd0e8b4d9eb7a
    分析:除了某一个数只出现了1 or 2次(出现次数%3==1 or 2),其余都出现了三次(或整数倍)。也就是说,如果有 模3加法(异或为模2加法),那么就很简单了,直接把所有数字按位相加
    Single Number的本质,就是用一个数记录每个bit出现的次数,如果一个bit出现两次就归0,这种运算采用二进制底下的位操作^是很自然的。Single Number II中,如果能定义三进制底下的某种位操作,也可以达到相同的效果,Single Number II中想要记录每个bit出现的次数,一个数搞不定就加两个数,用ones来记录只出现过一次的bits,用twos来记录只出现过两次的bits,ones&twos实际上就记录了出现过三次的bits,这时候我们来模拟进行出现3次就抵消为0的操作,抹去ones和twos中都为1的bits。

    public int singleNumber(int[] A) {
            int ones = 0;//记录只出现过1次的bits
            int twos = 0;//记录只出现过2次的bits
            int threes;
            for(int i = 0; i < A.length; i++){
                int t = A[i];
                twos |= ones&t;//要在更新ones前面更新twos
                ones ^= t;
                threes = ones&twos;//ones和twos中都为1即出现了3次
                ones &= ~threes;//抹去出现了3次的bits
                twos &= ~threes;
            }
            return ones; 
        }


    原文:https://blog.csdn.net/smile_watermelon/article/details/47748227

  • 相关阅读:
    android中kl布局文件加载失败解决办法
    android系统输入按键流程
    linux键值转android键值配置文件
    linux键值到Android键值的转换与自定义
    linux中ioctl的应用与说明
    zabbix邮件告警
    linux 双网关双IP设置
    随笔
    记录一次事故
    python解析.yml/.yaml文件--pyyaml模块(第三方)
  • 原文地址:https://www.cnblogs.com/twoheads/p/10553723.html
Copyright © 2011-2022 走看看