题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.*;
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
Arrays.sort(array);
int i = 0;
while(i<array.length-1){
if((array[i] ^ array[i+1]) == 0)
i = i + 2;
else{
num1[0] = array[i];
i++;
break;
}
}
while(i<array.length-1){
if((array[i] ^ array[i+1]) == 0)
i = i + 2;
else{
num2[0] = array[i];
break;
}
}
if(i == array.length-1)
num2[0] = array[array.length-1];
}
}
有一个很重要的点:如何判断一个数的二进制某一位是不是1???对1取&
对其排序后,将一个的数字保存下来!
注意:最后的判断,由于循环中存在i与i+1的比较,所以while中必须保证下面不能越界,i<array.length-1
,但是i是可能取到array.length-1这个数值的。所以最后需要最其进行一个判断!
把一个混乱的数组给规则化,即对其进行排序是一个常规想法!
异或做法:
怎么实现子数组的划分呢?对原数组从头到尾进行异或,最后出现的为这两个出现一次的数异或的结果。在这个结果的二进制表示中,至少有一位为1,因为这两个数不相同。那么,从该结果中找到第一个为1的位置,该位记为从最低位开始计数的第n位。
那么,划分的标准定为:从最低位开始计数的第n位是否为1。
因为出现两次的同一个数字,各个位数上都是相同的,所以一定被分到同一个子数组中,且每个子数组中只包含一个出现一次的数字。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.*;
public class Solution {
public int placeOfOne(int value){
int n = 1;
while((value & 1) != 1){
n++;
value = value >> 1;
}
return n;
}
public boolean isOne(int value,int n){
int i = 1;
while(i <= n){
if((value & 1) == 1)
return true;
value = value >> 1;
i++;
}
return false;
}
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int value = array[0];
for(int i=1;i<array.length;i++){
value ^= array[i];
}
int n = placeOfOne(value);
ArrayList<Integer> arr1 = new ArrayList();
ArrayList<Integer> arr2 = new ArrayList();
for(int i=0;i<array.length;i++){
if(isOne(array[i],n))
arr1.add(array[i]);
else
arr2.add(array[i]);
}
num1[0] = arr1.get(0);
for(int i=1;i<arr1.size();i++){
num1[0] ^= arr1.get(i);
}
num2[0] = arr2.get(0);
for(int i=1;i<arr2.size();i++){
num2[0] ^= arr2.get(i);
}
}
}
补充:
public boolean isOne(int value,int n){
return((value >> n-1) & 1) == 1;
}
这个函数可以更简化一些,注意右移的是n-1位。
而且placeOfOne()函数中要注意,一个整数右移的次数<32,之后为0!
参考:https://blog.csdn.net/ouyangyanlan/article/details/72668012