zoukankan      html  css  js  c++  java
  • 【leetcode】260. Single Number III

    Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

    For example:

    Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

    Note:

    1. The order of the result is not important. So in the above example, [5, 3] is also correct.
    2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

    Credits:
    Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.

    Subscribe to see which companies asked this question

    这题见过,常数空间,线性时间。

    第一反应就是异或。假如那两个数是a和b,异或完的值是a^b,之后怎么办呢。???一直没想出来

    实际上,可以根据a^b最低位非0的值,也就是在这个位上,a和b是不同的,那么根据这个条件可以把原来的vector分成两个vector,每个vector只包含一个出现一次的数,这样就很简单了。异或就可以得到这个数。


    位运算很多知识都忘了,来补一下:

    位运算应用口诀 
    清零取反要用与,某位置一可用或 
    若要取反和交换,轻轻松松用异或 
    移位运算 
    要点 1 它们都是双目运算符,两个运算分量都是整形,结果也是整形。 
        2 " < <" 左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2。 
        3 ">>"右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。 
        4 ">>>"运算符,右边的位被挤掉,对于左边移出的空位一概补上0。 
    位运算符的应用 (源操作数s 掩码mask) 
    (1) 按位与-- & 
    1 清零特定位 (mask中特定位置0,其它位为1,s=s&mask) 
    2 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask) 
    (2) 按位或-- | 
        常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask) 
    (3) 位异或-- ^ 
    1 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask) 
    2 不引入第三变量,交换两个变量的值 (设 a=a1,b=b1) 
        目 标          操 作              操作后状态 
    a=a1^b1        a=a^b              a=a1^b1,b=b1 
    b=a1^b1^b1      b=a^b              a=a1^b1,b=a1 
    a=b1^a1^a1      a=a^b              a=b1,b=a1 
    二进制补码运算公式: 
    -x = ~x + 1 = ~(x-1) 
    ~x = -x-1 
    -(~x) = x+1 
    ~(-x) = x-1 
    x+y = x - ~y - 1 = (x|y)+(x&y) 
    x-y = x + ~y + 1 = (x|~y)-(~x&y) 
    x^y = (x|y)-(x&y) 
    x|y = (x&~y)+y 
    x&y = (~x|y)-~x 
    x==y:    ~(x-y|y-x) 
    x!=y:    x-y|y-x 
    x < y:    (x-y)^((x^y)&((x-y)^x)) 
    x <=y:    (x|~y)&((x^y)|~(y-x)) 
    x < y:    (~x&y)|((~x|y)&(x-y))//无符号x,y比较 
    x <=y:    (~x|y)&((x^y)|~(y-x))//无符号x,y比较 
    应用举例 
    (1) 判断int型变量a是奇数还是偶数            
    a&1  = 0 偶数 
          a&1 =  1 奇数 
    (2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1 
    (3) 将int型变量a的第k位清0,即a=a&~(1 < <k) 
    (4) 将int型变量a的第k位置1, 即a=a|(1 < <k) 
    (5) int型变量循环左移k次,即a=a < <k|a>>16-k  (设sizeof(int)=16) 
    (6) int型变量a循环右移k次,即a=a>>k|a < <16-k  (设sizeof(int)=16) 
    (7)整数的平均值 
    对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法: 
    int average(int x, int y)  //返回X,Y 的平均值 
    {    
        return (x&y)+((x^y)>>1); 

    (8)判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂 
    boolean power2(int x) 

        return ((x&(x-1))==0)&&(x!=0); 

    (9)不用temp交换两个整数 
    void swap(int x , int y) 

        x ^= y; 
        y ^= x; 
        x ^= y; 

    (10)计算绝对值 
    int abs( int x ) 

    int y ; 
    y = x >> 31 ; 
    return (x^y)-y ;        //or: (x+y)^y 

    (11)取模运算转化成位运算 (在不产生溢出的情况下) 
            a % (2^n) 等价于 a & (2^n - 1) 
    (12)乘法运算转化成位运算 (在不产生溢出的情况下) 
            a * (2^n) 等价于 a < < n 
    (13)除法运算转化成位运算 (在不产生溢出的情况下) 
            a / (2^n) 等价于 a>> n 
            例: 12/8 == 12>>3 
    (14) a % 2 等价于 a & 1        
    (15) if (x == a) x= b; 
                else x= a; 
            等价于 x= a ^ b ^ x; 
    (16) x 的 相反数 表示为 (~x+1) 

    (17)求x转化为二进制之后包含1的数量

        int count = 0;

        while(x)

      {

        count++;

        x = x & (x - 1);

        }

     最后得到的count 即为x转化为二进制之后包含1的数量


    实例 

        功能              |          示例            |    位运算 
    ----------------------+---------------------------+-------------------- 
    去掉最后一位            | (101101->10110)              | x >> 1 
    在最后加一个0          | (101101->1011010)           | x < < 1 
    在最后加一个1          | (101101->1011011)           | x < < 1+1 
    把最后一位变成1       | (101100->101101)             | x | 1 
    把最后一位变成0       | (101101->101100)             | x | 1-1 
    最后一位取反            | (101101->101100)             | x ^ 1 
    把右数第k位变成1      | (101001->101101,k=3)      | x | (1 < < (k-1)) 
    把右数第k位变成0      | (101101->101001,k=3)      | x & ~ (1 < < (k-1)) 
    右数第k位取反          | (101001->101101,k=3)       | x ^ (1 < < (k-1)) 
    取末三位                 | (1101101->101)                 | x & 7 
    取末k位                  | (1101101->1101,k=5)         | x & ((1 < < k)-1) 

    取右数第k位                | (1101101->1,k=4)              | x >> (k-1) & 1 

    把末k位变成1              | (101001->101111,k=4)        | x | (1 < < k-1) 
    末k位取反                  | (101001->100110,k=4)         | x ^ (1 < < k-1) 
    把右边连续的1变成0     | (100101111->100100000)     | x & (x+1) 
    把右起第一个0变成1     | (100101111->100111111)     | x | (x+1) 
    把右边连续的0变成1     | (11011000->11011111)         | x | (x-1) 
    取右边连续的1            | (100101111->1111)              | (x ^ (x+1)) >> 1 
    去掉右起第一个1的左边 | (100101000->1000)              | x & (x ^ (x-1)) 
    判断奇数       (x&1)==1 
    判断偶数 (x&1)==0


    class Solution {
    public:
        int GetXor(vector<int>& vec){
            int ret=0;
            for(int i=0;i<vec.size();i++){
                ret^=vec[i];
            }
            return ret;
        }
        vector<int> singleNumber(vector<int>& nums) {
            int a=GetXor(nums);
            int b=1;
            while((a&1)==0){
                a>>=1;
                b<<=1;
            }
            vector<int> vec1,vec2;
            for(int j=0;j<nums.size();j++){
                if((nums[j]&b)==0)
                    vec1.push_back(nums[j]);
                else 
                    vec2.push_back(nums[j]);
            }
            vector<int> ret;
            int n1=GetXor(vec1);
            ret.push_back(n1);
            int n2=GetXor(vec2);
            ret.push_back(n2);
            return ret;
        }
    };
  • 相关阅读:
    Flink基础之实现WordCount程序(Java版本多种写法)
    Redis 在Springboot 中反序列化 LocalDateTime 时报错
    JVM(五)- 堆
    JVM(四)- 虚拟机栈
    JVM(三)- 程序计数器(PC 寄存器)
    JVM(二)- 运行时数据区概述及线程
    JVM(一)
    phpstudy后门漏洞复现
    primefaces 5.x 表达式注入
    ueditor(v1.4.3)文件上传getshell实战复现
  • 原文地址:https://www.cnblogs.com/LUO77/p/5622564.html
Copyright © 2011-2022 走看看