// 给定一个非空整数数组,
// 1)除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。稍微拓展下,
// 2)加深一步:有两个元素分别各出现一次,且两个元素一个是奇数,一个是偶数又该如何找到这两个数字。
// 3)更进一步:仅仅告诉你就是有两个数不同,且各出现一次,如何找出这两个数字
// 说明:
// 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
//
// 示例 1:
// 输入: [2,2,1]
// 输出: 1
// 示例 2:
//
// 输入: [4,1,2,1,2]
// 输出: 4
//
// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/single-number
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public class NumberOnce {
public int singleNumber(int[] nums) {
if (null == nums || nums.length == 0) {
throw new IllegalArgumentException();
}
return singleNumber(nums, nums.length);
}
/**
* 从指定长度的数组里面找只出现一次的数
*
* @param nums
* @param length
* @return
*/
private int singleNumber(int[] nums, int length) {
int numOnce = nums[0];
if (length == 1)
return numOnce;
// 采用异或操作
for (int i = 1; i < length; i++) {
numOnce = numOnce ^ nums[i];
}
return numOnce;
}
// 描述进一步,如果告诉输入里面有两个元素分别只出现一次,且两个元素一个奇数一个偶数,
// 线下时间复杂度下能否找出这两个数字
public int[] twoOddEvenNumber(int[] nums) {
if (null == nums || nums.length < 2) {
throw new IllegalArgumentException();
}
// 因为两个只出现一次的数分奇偶,所以可以按奇偶把元素重新分配
int oddNum = 0;
int evenNum = 0;
for (int tem : nums) {
// 偶数
if (tem % 2 == 0) {
evenNum = evenNum ^ tem;
} else {
oddNum = oddNum ^ tem;
}
}
int[] retArr = new int[2];
// i的值就是奇数数值的有效个数,j的值就是偶数数组的有效长度
retArr[0] = oddNum;
retArr[1] = evenNum;
return retArr;
}
// 描述进一步,如果告诉输入里面有两个元素分别只出现一次,
// 线下时间复杂度下能否找出这两个数字
public int[] twoNumber(int[] nums) {
if (null == nums || nums.length < 2) {
throw new IllegalArgumentException();
}
int orNum = singleNumber(nums);// 找出两个不同数的异或结果
int offset = 0;
// 从低位开始找第一个为零的bit位,以此作为数组区分的依据,因为是int,所以最多循环32次
for (int i = 0; i < 32; i++) {
// 说明最低位是1,最低位不同
if ((orNum ^ (orNum - 1)) == 1) {
break;
} else {
orNum = orNum >> 1;
offset++;
}
}
int bitOne = 0;
int bitZero = 0;
for (int tem : nums) {
// 先把tem左移 offset位赋值给临时变量m
int m = tem >> offset;
//把位为1的分组异或
if ((m ^ (m - 1)) == 1) {
bitOne = bitOne ^ tem;
} else {
bitZero = bitZero ^ tem;
}
}
int[] retArr = new int[2];
// i的值就是奇数数值的有效个数,j的值就是偶数数组的有效长度
retArr[0] = bitOne;
retArr[1] = bitZero;
return retArr;
}
public static void main(String[] args) {
int[] input = { 2, 2, 1, 1, 3,3,6, 4 };
int[] out = new NumberOnce().twoNumber(input);
System.out.println(out[0]+","+out[1]);
// System.out.println(10^9);
}
}