剑指offer-数组中只出现1次的数字
2018-03-31 15:24
309 查看
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。地址: 牛客链接
问题分析
首先,若允许用额外空间的话,那么可以遍历数组,用set存储,如果当前元素,set中已经存在了,那么将该元素从set中移除;如果set中不存在当前元素,那么将之装入set中。最终,偶数次的元素全部移除,set中只有奇数次的元素。即为所求实际上,该题考察的不用额外空间,考察位运算的知识。
若将这个数组求异或和,那么出现偶数次的元素相异或的结果为0,所以,最终的异或和 eor = a^b (假如只有a,b出现了奇数次)。那么对于eor 而言,必然至少有一位不为0,并且在那个位置上,a要是为1,b肯定为0;b要是为1,a肯定为0。
所以,如果我们对于 eor 从右往左找到第一个不为0的位置,那么便可以区分a,b。 举例说明: a = 1110, b = 0100,那么 a^b = 1010。在从右往左数第2位上,xor不为0 ,a为1,b为0,这样便可以区分 a,b。
问题又来了,如何得到一个二进制形式的最右边的1呢?
遍历,与 1 << x 相与,直至结果不为0
eor & (-eor)
eor & (~eor + 1)(其实道理和上一个一样,因为位运算是对补码进行的,一个负数的补码,便是他对应正数的补码取反,加1)
举例,对于a = 1110, b = 0100,那么 a^b = 1010。 eor & (~eor + 1) 的结果便是 0010。
利用rightOne 便可以区分出 a 和 b,所以再次遍历数组,只有与 rightOne相与结果为1的才进行异或和,这样便淘汰了 a 或者 b 中的一个,而最终的异或肯定也是 a 或者 b。那么将 该异或和与 eor 相异或,那么结果是 两者中的另一个。 理由: a ^ b = c,那么 c ^ a = b
经验教训
异或运算的性质(奇偶个数异或和性质)如何得到一个二进制形式的最右边的1呢: eor & (-eor) 或者 eor & (~eor + 1)
该题可以引申出三个问题:
如果一个数组中,只有一个数字出现了奇数次,其他都出现了偶数次,那么如何得到该奇数次的数字
求该数字的异或和,异或和即为所求
如果一个数组中,有两个数字出现了奇数次,其他都出现了偶数次,那么如何得到该奇数次的数字
方法同本题一样
若数组中有一个数出现了一次,剩下的数出现了K次,如何求出出现了 1 次的数字
将所有的数都转化为K进制形式,然后将所有K进制形式每一位相加,最后将每一位 对K取模,将每一位取模后的结果转换为十进制,即为所求。
举例,7出现1次,4出现3次,那么 7的三进制形式为 21,4的三进制形式为 11。每一位累加结果为 2*1 + 1* 3 =5, 1*1 + 1*3 = 4。取模结果为 21,转为十进制 7
相应位运算的题:
剑指offer-二进制中1的个数
剑指offer-数值的整数次方
代码实现
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { if (array == null || array.length == 0) { return; } int eor = 0; for (int i = 0; i < array.length; i++) { eor ^= array[i]; } //int rightOne = eor & (~eor + 1); int rightOne = eor & (-eor); int firstValue = 0; for (int i = 0; i < array.length; i++) { if ((rightOne & array[i]) != 0) { firstValue ^= array[i]; } } num1[0] = firstValue; num2[0] = firstValue ^ eor; return; } }
相关文章推荐
- 剑指offer系列之39:数组中只出现1次的数字
- 剑指offer-统计一个数字在排序数组中出现的次数
- 剑指offer第38题 数字在排序数组中出现的次数
- 数组中只出现1次的两个数字
- 剑指offer——面试题38:数字在排序数组中出现的次数(利用二分查找来找第一次和最后一次的位置)
- 《剑指offer》刷题笔记(时间效率):数组中出现次数超过一半的数字
- 数组中出现次数超过一半的数字——剑指offer
- 《剑指offer》:[40]数组中只出现一次的数字
- 《剑指offer》-数组中只出现一次的数字
- 剑指offer:数字在排序数组中出现的次数
- 《剑指Offer》学习笔记--面试题40:数组中只出现一次的数字
- 【算法】数组中只出现1次的两个数字(百度面试题)
- 找出数组中只出现1次的两个数字(经典面试题)
- 剑指Offer(Java版):数组出现一次的数字
- 【剑指offer系列】 数字在排序数组中出现的次数___38
- 《剑指offer》-数字在排序数组中出现的次数
- 异或的应用 及剑指offer 面试 40 数组中只出现一次的数字
- 剑指offer-第六章面试中的各项能力(数组中只出现一次的数字)
- 剑指offer——数字在排序数组中出现的次数
- 白话经典算法系列之十二 数组中只出现1次的两个数字(百度面试题)