位操作(Bit Manipulation)—— Single Number 2/3

目录

Single Number 2 :

思路:

难点:

code:

Single Number 3 :

思路:

难点:

code:

补充:


Single Number 2 :

给定一个非空的整数数组,每个元素都会出现三次,只有一个出现一次。找到那个只出现一次的元素

思路:

对每一个位上出现的所有元素的1的个数统计,如果是出现三次的数,那么模3的结果为0;如果是出现1次的数,那么模3的结果为1。这样就可以利用取模的结果找出待求的数。

难点:

如何统计每一个位上出现1的总个数?这个问题可以通过两个步骤解决,第一步是循环,外循环是针对32个位置,内循环是针对每个数;第二步是判断,对每个数字的每个位置判断是否为1.

code:

//注意到,出现3次,对每个位上的1的个数做出统计,发现会被3整除也就是模3为0
//我们对每一位统计,并且对统计结果模3,只出现一次的数模3过后的结果为1

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for(int i=0;i<32;i++){
            int sum = 0;
            for(int n:nums){
                sum += (n>>i)&1;
            }
            res |= sum%3 << i;
        }
        return res;
    }
}

Single Number 3 :

给定一个数字数组num,其中正好有两个元素只出现一次,而所有其他元素恰好出现两次。查找只出现一次的两个元素。

思路:

首先对整个num进行分组,使得待求的两个数字各自处于一个分组中,这样两个分组单独求出一个元素即可。

难点:

如何分组?可以对整个数组求抑或运算。对于非待求元素,都出现了两次,因此,抑或运算的结果相当与待求元素做抑或运算。那么只需要找到这个结果中的任意一位为1,自说明,待求结果的两个元素在这个位置上不同。可以利用这一点分组。

code:

//思路:首先对整个nums抑或,这个结果是需要求得的两个不同的数字的抑或的结果
//找到这个结果中的一个为 1 的位(为一表示,这两个不同的数字在这个位置上一个为0,一个为1)
//根据这个条件,将整个nums分成两组,每组单独抑或的结果,就是,想要求得的结果

class Solution {
    public int[] singleNumber(int[] nums) {
        int div = 0;
        for(int num : nums){
            div ^= num;
        }
        //取出最低位的1
        //int d = Integer.lowestOneBit(div);
        div &= -div;//负值的表示方法
        int res1 =0;
        int res2 =0;
        for(int num : nums){
            if((div&num) != 0){
                res1 ^= num;
            }
            else{
                res2 ^= num;
            }
        }
        return new int[]{res1,res2};
    }
}

补充:

1、Integer类中的highestOneBit是如何实现的?

参考 https://blog.youkuaiyun.com/u011544437/article/details/78497190

/**
     * Returns an {@code int} value with at most a single one-bit, in the
     * position of the highest-order ("leftmost") one-bit in the specified
     * {@code int} value.  Returns zero if the specified value has no
     * one-bits in its two's complement binary representation, that is, if it
     * is equal to zero.
     *
     * @param i the value whose highest one bit is to be computed
     * @return an {@code int} value with a single one-bit, in the position
     *     of the highest-order one-bit in the specified value, or zero if
     *     the specified value is itself equal to zero.
     * @since 1.5
     */
    public static int highestOneBit(int i) {
        // HD, Figure 3-1
        i |= (i >>  1);
        i |= (i >>  2);
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);
        return i - (i >>> 1);
    }

    /**
     * Returns an {@code int} value with at most a single one-bit, in the
     * position of the lowest-order ("rightmost") one-bit in the specified
     * {@code int} value.  Returns zero if the specified value has no
     * one-bits in its two's complement binary representation, that is, if it
     * is equal to zero.
     *
     * @param i the value whose lowest one bit is to be computed
     * @return an {@code int} value with a single one-bit, in the position
     *     of the lowest-order one-bit in the specified value, or zero if
     *     the specified value is itself equal to zero.
     * @since 1.5
     */
    public static int lowestOneBit(int i) {
        // HD, Section 2-1
        return i & -i;
    }

例子:highestOneBit:保留最高位的1,低位都置为0

        i |= (i >>  1);//使得最高位1以及它的后面一位变成1:1000|0100 = 1100
        i |= (i >>  2);//使得前四位变成1:1100|0011 = 1111;
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);//使得最高位及其以后的低位全部变成1:00111111...
        return i - (i >>> 1);//无符号左移,再相减 00111111...- 00011111.. = 00100000..

例子:lowestOneBit:保留低位的1,高位都置为0

       return i & -i;

       实验代码:

		System.out.println(Integer.toBinaryString(4));
		System.out.println(Integer.toBinaryString(-4));
		System.out.println(Integer.toBinaryString(4&-4));
		
		System.out.println(Integer.toBinaryString(5));
		System.out.println(Integer.toBinaryString(-5));
		System.out.println(Integer.toBinaryString(5&-5));
		
		System.out.println(Integer.toBinaryString(6));
		System.out.println(Integer.toBinaryString(-6));
		System.out.println(Integer.toBinaryString(6&-6));

       结果:

100
11111111111111111111111111111100
100
101
11111111111111111111111111111011
1
110
11111111111111111111111111111010
10

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值