• [LeetCode] 137. Single Number II (位操作)


    传送门

    Description

    Given an array of integers, every element appears three times except for one, which appears exactly once. 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)的条件下,找出这个出现一次的数。

    题解:

    方法一:因为除了一个数外,其他每个数都出现三次,因此枚举每一位二进制位,统计每一位上这些数为1的数总共有多少个,然后与3相模,如果余1,证明这个出现一次的数的二进制在这位上为1。(此法是通用方法,适用于除一个数外,其他数出现k次,那么只需模k即可)

    class Solution {
    public:
        //12ms
        int singleNumber(vector<int>& nums) {
            int res = 0;
            for (int i = 0;i < 32;i++){
                int cnt = 0;
                int mask = 1 << i;
                for (int j = 0;j < nums.size();j++){
                    if (nums[j] & mask){
                        cnt++;
                    }
                }
                if (cnt % 3){
                    res |= mask;
                }
            }
            return res;
        }
    };
    

      

    方法二:用两个变量记录所有数二进制位中哪些位为1出现一次,哪些二进制位为1出现两次,之所以只需两个,是因为同一个数最多只出现三次,因此我们可以选定状态 00 -> 01 -> 10来记录,那么我们用ones表示哪些位为1出现一次(模3后出现一次),用twos表示哪些位为1出现两次(模3后出现一次),当ones和twos某一二进制位上同时为1说明这位为1出现了三次,那么我们此时将ones和twos的这位二进制位清0,最后ones就是答案。

    class Solution {
    public:
        //9ms
        int singleNumber(vector<int>& nums) {
            int ones = 0,twos = 0,threes = 0;
            for (unsigned int i = 0;i < nums.size();i++){
                //以下两句代码不能颠倒次序,如若颠倒,则一个数先记录于ones,
                //然后twos的值依赖于ones及这个数,那么这个数就被统计了两次
                twos |= (nums[i] & ones);  //记录有哪些二进制位为1且出现两次存于twos
                ones ^= nums[i];           //记录有哪些二进制位为1且出现一次存于ones
    
                //以下三句是清零操作
                threes = ones & twos;
                ones &= ~threes;
                twos &= ~threes;
            }
            return ones;
        }
    };
    

     

    另外,方法二代码可精简如下:ones与twos的含义与上述相同。

    class Solution {
    public:
        //9ms
        int singleNumber(vector<int>& nums) {
            int ones = 0,twos = 0;
            for (unsigned int i = 0;i < nums.size();i++){
                //ones&~twos以及twos&~ones都是为了清零操作,两者二进制位都为1时清零
                ones = (ones ^ nums[i]) & (~twos);
                twos = (twos ^ nums[i]) & (~ones);
            }
            return ones;
        }
    };
    

      

  • 相关阅读:
    Mybatis学习-ResultMap
    MySql模糊查询 concat()函数
    Spring学习-依赖注入
    Struts2学习-struts执行过程简述
    Struts2学习-jsp中超链接传参问题
    Struts2学习-struts.xml文件配置
    第四次作业
    第三次作业
    Django -Ajax
    Django -ORM
  • 原文地址:https://www.cnblogs.com/ZhaoxiCheung/p/7397289.html
Copyright © 2020-2023  润新知