数字只出现一次
代码:
public static void main(String[] args) {
// int[] arr = {2, 2, 1};
// int num = singleNumber(arr);
// System.out.println(num);
// int[] arr={2,1,2,3,4,1};
// int[] nums = singleNumber2(arr);
// System.out.println(Arrays.toString(nums));
// int[] arr={2,2,3,2};
int[] arr={0,1,0,1,0,1,99};
int num = singleNumber3(arr);
System.out.println(num);
}
/**
* 只出现一次的数字 其余数字都出现两次,只有一个数字出现一次
* 达到只使用线性的时间复杂度 不使用额外的空间
* 使用异或运算 相同的元素进行异或运算 为0 0与任何元素异或都是元素本身
*
* @Date: 2020/6/9 23:15
* @Author: fuGuoWen
* @Return int 返回出现一次的数字
* @Throws 无
*/
public static int singleNumber(int[] nums) {
int result = 0;
for (int i = 0; i < nums.length; i++) {
result ^= nums[i];
}
return result;
}
/**
* 恰好有两个元素出现一次,其余的元素都是出现两次
* 解决方案:
* 1.对所有的元素做异或操作
* 2.对异或以后的结果取低位第一个为1 的值 temp
* 3.对整个元素继续进行遍历,如果当前元素的值与temp 最高位的值相同 返回的值不为0,
* 如果当前元素的值与temp 最高位的值不同,返回的是0
*
* 算法 具备 线性的时间复杂度 和常量的空间复杂度
*
* @Date: 2020/6/9 23:28
* @Author: fuGuoWen
* @Return int[] 整形数组
* @Throws 无
*/
public static int[] singleNumber2(int[] nums) {
int result=0;
/** 第一步: 所有的元素进行异或,会得到唯一的两个元素的异或值 */
for(int i=0;i<nums.length;i++){
result^=nums[i];
}
/** 第二步 获得result低位的第一个不为0 的值 */
int temp = 1;
while (result != 0) {
if ((result & 1) == 1) {
break;
}
temp <<= 1;
result >>= 1;
}
int[] arr=new int[2];
for(int i=0;i<nums.length;i++){
if((nums[i]&temp)==0){
/**
* 第三步 对所有的元素进行与最高位的元素的值进行与运算 与最高位元素相同的值 进行的计算不为0
* 与最高位元素相同的值 进行的计算结果为0
* */
arr[0]^=nums[i];
}else{
arr[1]^=nums[i];
}
}
return arr;
}
/**
* 只有一个元素出现了一次,其他的元素都是出现了三次
* 解决思路
* 1.
* @Date: 2020/6/10 0:26
* @Author: fuguowen
* @Return
* @Throws
*/
public static int singleNumber3(int[] nums) {
/** 第一步 遍历数组的每一位按照二进制位进行累加 */
int[] bits = new int[32];
for (int i = 0; i < 32; i++) {
for (int j = 0; j < nums.length; j++) {
bits[i] += (nums[j] & 1);
nums[j] >>= 1;
}
}
/**
* 第二步 高位元素存储在下标比较大的位置
* 从高位元素进行遍历,先进行右移,再进行跟3取模,求余,最后获得元素就是只出现一次的元素
* */
int result = 0;
for (int i = 31; i >= 0; i--) {
result <<= 1;
result += (bits[i] % 3);
}
return result;
}