LeetCode进阶记录--136

背景

上次面试,考的是LeetCode136题目,真要是实现,其实方法会比较多(遍历或记录),但明显考点不在此;自己的思路是需要把相同的数进行中和(此前做过类似的题目),不过最后还是没有搞出来,最后面试官提示了使用异或操作;虽然此前在刷leetcode时有做过类似的题目,但是印象不深,也没有太理解异或操作的特点,所以导致这次简单的题目fail了。今天单拿出来又仔细练习了一番。

异或的特点

    1)0^n=n;解释:0与任何数异或的结果为该数值;
    2)n^n=0;解释:两个相等的值进行异或,则结果为0。

所以说,通过异或操作,就能实现将相同的数值进行中和的效果。

题目

	给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
	说明:
	你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
	示例 1:
	输入: [2,2,1]
	输出: 1
	示例 2:
	输入: [4,1,2,1,2]
	输出: 4
	来源:力扣(LeetCode)
	链接:https://leetcode-cn.com/problems/single-number
	著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

答案

public int singleNumber1(int[] nums) {
    // 1  0^n=n;
    // 2  n^n=0
    int result = 0;
    for (int i : nums) {
        result ^= i;
    }
    return result;
}

题目进阶

如果输入参数有2个数只出现1次,而其他数值都会出现2次,找出这两个只出现1次的数值;例如,[1,2,2,1,3,4],目的找到[3,4]。

思路:
1.需要想办法将输入数组分成两组,同时确保把3和4分开到两个组中;
1.1 如何做到将3,4分开放置到2个组中?找出3,4数值的差异部分(该题目中是3,4),然后用该部分来区分3和4;
1.2 如何找到3,4的差异部分,可以对3,4进行异或操作,相同部分的二进制会为0,而不同的部分会为1;
1.3 因为除了3,4之外的其他数值都会出现两次,所以说对所有数值在进行异或之后,其结果仍旧是3,4的差异部分(异或的原因);
1.4 使用异或的结果中的任意1位非0位,对输入数组进行分组即可达到目的。
2.在将输入数值分成2个组之后,3和4会分别在2个组中,再分别对两个组进行异或操作即可把两个组中不同的数值取出来。

public int singleNumber1(int[] nums) {
    // 1  0^n=n;
    // 2  n^n=0
    int result = 0;
    for (int i : nums) {
        result ^= i;
    }
    return result;
}

    public int[] split(int[] nums) {
        int[] result = new int[2];
        // 计算出所有数值的异或的结果
        int result1 = singleNumber1(nums);
        int result2 = 0x80; // 1000 0000
        // 找到左侧第一个二进制不为0的数值,用于对输入数组进行分组
        while((result2 & result1) == 0) {
            result2 >>= 1;
        }
        List<Integer> left = new ArrayList<>();
        List<Integer> right = new ArrayList<>();
        // 对输入数组进行分组
        for (int i : nums) {
            if ((i & result2) == 0) {
                left.add(i);
            } else {
                right.add(i);
            }
        }
        // 对两个数组分别进行异或操作,以计算出2个只出现1次的数值
        result[0] = singleNumber1(left.stream().mapToInt(Integer::valueOf).toArray());
        result[1] = singleNumber1(right.stream().mapToInt(Integer::valueOf).toArray());
        return result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值