原题地址
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

Leetcode 137 Single Number II 仅出现一次的数字的更多相关文章

  1. LeetCode 137. Single Number II(只出现一次的数字 II)

    LeetCode 137. Single Number II(只出现一次的数字 II)

  2. LeetCode 137 Single Number II(仅仅出现一次的数字 II)(*)

    翻译 给定一个整型数组,除了某个元素外其余的均出现了三次. 找出这个元素. 备注: 你的算法应该是线性时间复杂度. 你能够不用额外的空间来实现它吗? 原文 Given an array of inte ...

  3. [LeetCode] 137. Single Number II 单独数 II

    Given a non-empty array of integers, every element appears three times except for one, which appears ...

  4. [LeetCode] 137. Single Number II 单独的数字之二

    Given a non-empty array of integers, every element appears three times except for one, which appears ...

  5. 详解LeetCode 137. Single Number II

    Given an array of integers, every element appears three times except for one, which appears exactly ...

  6. leetcode 137. Single Number II ----- java

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

  7. Java [Leetcode 137]Single Number II

    题目描述: Given an array of integers, every element appears three times except for one. Find that single ...

  8. LeetCode 137 Single Number II 数组中除了一个数外,其他的数都出现了三次,找出这个只出现一次的数

    Given an array of integers, every element appears three times except for one, which appears exactly ...

  9. Java for LeetCode 137 Single Number II

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

随机推荐

  1. 实验六 MapReduce实验:二次排序

    实验指导: 6.1 实验目的基于MapReduce思想,编写SecondarySort程序. 6.2 实验要求要能理解MapReduce编程思想,会编写MapReduce版本二次排序程序,然后将其执行 ...

  2. 线段树 by yyb

    线段树 by yyb Type1 维护特殊信息 1.[洛谷1438]无聊的数列 维护一个数列,两种操作 1.给一段区间加上一个等差数列 2.单点询问值 维护等差数列 不难发现,等差数列可以写成\(ad ...

  3. 【BZOJ5321】[JXOI2017]加法(贪心)

    [BZOJ5321][JXOI2017]加法(贪心) 题面 BZOJ 洛谷 题解 显然二分答案,算一下每个点至少要覆盖的次数.从左往右考虑如果这个点覆盖次数不够,就会选择覆盖这个点的.右端点最大的线段 ...

  4. [SCOI2007]压缩(区间dp)

    神仙题,看了半天题解才看明白... 因为题目里说如果没有m,会自动默认m在最前面. 我们设计状态为dp[l][r][0/1]为在区间l到r中有没有m的最小长度. 转移:枚举我们要压缩的起点,dp[l] ...

  5. spring activemq 整合

    创建maven项目 项目目录结构为 首先配置相关maven依赖 <!-- 版本管理 --> <properties> <springframework>4.1.8. ...

  6. 如何刻录cd音乐

    用nero,选择cd,音乐光盘(第一个)可以添加入wav,MP3等.刻录即可.

  7. js,jquery 获取滚动条高度和位置, 元素距顶部距离

    一,获取滚动条高度和位置 jQuery 获取览器显示区域的高度: $(window).height();  获取浏览器显示区域的宽度:$(window).width(); 获取页面的文档高度:$(do ...

  8. OpenLayers学习笔记(六)— 拖拽叠加层overlayer

    是在官网例子基础上增加的拖拽功能 GitHub:八至 作者:狐狸家的鱼 本文链接:拖拽叠加层overlayer 全部代码 <!DOCTYPE html> <html> < ...

  9. 【洛谷P4144】大河的序列

    题目大意:给定一个长度为 N 的序列,求序列中连续区间最大的(或和加与和)是多少. 题解: 引理:任意两个数 \(i, j\),若 \(i>j\),则在二进制表示下,i 对应的二进制串的字典序一 ...

  10. 第五篇-以显式意图(Explicit Intent)跳往其它Activity

    此项目基于第四篇. Intent(意图) Explicit Intent(显式意图): 清楚指明需要前往的Activity的名称 用于APP内部的连接 Inplicit Intent(隐式意图): 不 ...