位运算:1.single number,找出数组中出现一位的数字

基础知识:

任何数和 0 做异或运算,结果仍然是原来的数,即 a⊕0=a

任何数和其自身做异或运算,结果是 0,即 a⊕a=0

异或运算满足交换律和结合律,即 aba=baa=b(aa)=b0=b

使用位运算符可以实现 O(1) 的空间复杂度。

异或运算:x ^ 0 = x​ , x ^ 1 = ~x

与运算:x & 0 = 0 , x & 1 = x

singgle number1:整数类型的数组,数组中只有一个元素只出现一次,其余元素都出现2次。你需要找出只出现一次的元素

import java.util.*;
public class Solution {
    /**
     *
     * @param A int整型一维数组
     * @return int整型
     */
    public int singleNumber (int[] A) {
        int num=0;
        for (int i=0;i< A.length;i++){
            num ^=A[i];
        }
        return num;//最后结果即出现1次的那个数
    }
}

single number2:整数类型的数组,数组中只有一个元素只出现一次,其余元素都出现3次。你需要找出只出现一次的元素

基础知识:

hashset:

它存储唯一元素并允许空值

它由HashMap支持

它不保持插入顺序

它不是线程安全的

import java.util.*;
public class Solution {
    public int singleNumber(int[] A) {
           int sumarray=0,sumset=0;
           HashSet<Integer> set=new HashSet<>();
           for(int a:A){
               sumarray+=A[a];//所有的数加起来
               set.add(A[a]);//set存放唯一元素(不重复)
           }
           for(int s:set){      //将每个元素相加(只出现一次)
               sumset+=s;
           }
           return (3*sumset-sumarray)/2;
    }
}

逐位考虑

我们单独看二进制某一位,先不看单独的那个数,其他所有数字都出现了 3 次,所以那一位是 1 的个数一定是 3 的倍数。

再考虑这个出现一次的数,如果这一位是 1 ,那么这一位 1 的次数模 3 为 1 ,否则的话模 3 就是 0 。

那么就很简单了,统计一下有多少个数这一位上是 1 ,然后模 3 取余数,结果就是这个单独的数这一位上的值了。

遍历 32 位整数的每一位,就可以得到这个单独的数是多少了。

推广到一般情况:

如果其他数都出现了 k次,一个数出现了一次。那么如果 k 是偶数,还是把所有的数异或起来就行了。如果 k 是奇数,那么统计每一位是 1 的个数,然后模 k 取余数就能得到那个单独的数了。

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


once转移情况:

Once=o,twice=0,x=1

Once=1,twice=0,x=1

总结:once^x=1,twice=0     =>  once=(once^x) & (~twice)

 

twice转移情况:

Once=1,twice=0,x=1

Once=0,twice=1,x=0

总结:twice^x=1,twice^once=1    =>  twice=(twice^x) & (twice^once) 因为once 已经抢先一步转移过了,所以值已经变掉了,这两种情况下,once 都会转移到 0 ,所以判断条件直接用转移后的 once=0 就行了,随后转移就是 twice = (x^twice) & (~once) 。

 

import java.util.*;
public class Solution {
    public int singleNumber(int[] A) {
           int once=0,twice=0;
           for(int num:A){
               once=(once^num) &(~twice);
               twice=(twice^num) &(~once);
           }
        return once;//出现一次的
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值