1.数组中除了两个数只出现过一次,其他的均出现过两次,请找出这两个只出现过一次的数。
例如:{10,9,8,7,6,6,7,8,9,10,5,5,4,3};4和3只出现过一次,请找出出现过一次的数。首先想到的代码应该是上一个提到的遍历两次取出没有找到的相同的数字,代码如下:
public static List findOnlyNum(int[] array) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < array.length; i++) {
int j = 0;
for (; j <= array.length; j++) {
if (i == j) {
continue;
}
if (j == array.length) {
break;
}
if (array[i] == array[j]) {
break;
}
}
if (j == array.length) {
list.add(array[i]);
}
}
return list;
}
那么我们再用上一个提到的高大上的方法在想想有没有更好的解决办法。我们知道运用异或操作得到唯一一次出现的数字,如果我们能将这两个只出现过一次的数字划分开,对划分开的两个序列行进异或,那么就可以等到的我们想要找的两个数。第一步:我们需要找到一个条件,给这两个出现过一次的数找出可以区分的条件。相同的数异或等到的结果0,那么整个序列异或的结果就是这两个出现过一次的数的异或。
public static Integer findOnlyNum(int[] array){
int result = 0;
for(int i = 0 ;i<array.length;i++){
result^=array[i];
}
return result;
}
第二步:找出他们的不同之处,前面我们讲过,异或按位操作是相同的为0 ,不同的为1,那么这两个数异或的结果转换成2进制时,低位出现第一个1是就可以区分他们了。
String binaryResult = Integer.toBinaryString(result);
int index = binaryResult.length() - (binaryResult.lastIndexOf("1")+1);
第三步:在index位为1的分为一组,为0的分为一组,将序列划分为两个序列,这样就能得出我们想要的结果了。
int result1 = 0;
int result2 = 0;
for(int i =0;i<array.length;i++){
if(((array[i]>>index)&1)==1){
result1^= array[i];
}else{
result2^=array[i];
}
}
完整代码如下所示:
/**
* 找出數組b里面不成对出现的2个数字
* @param a
* @return
*/
public static List<Integer> findNum(int[] b){
List<Integer> list = new ArrayList<Integer>();
String binaryResult = Integer.toBinaryString(findOnlyNum(b));
int index = binaryResult.length() - (binaryResult.lastIndexOf("1")+1);
int result1 = 0;
int result2 = 0;
for(int i =0;i<b.length;i++){
if(((b[i]>>index)&1)==1){
result1^= b[i];
}else{
result2^=b[i];
}
}
list.add(result1);
list.add(result2);
return list;
}
/**
* 找出數組b里面不成对出现的唯一一个数字
* @param a
* @return
*/
public static Integer findOnlyNum(int[] a){
int result = 0;
for(int i = 0 ;i<a.length;i++){
result^=a[i];
}
return result;
}
2.连续自然数1~1000,其中少了一个数字,怎样用常数时间复杂度找出那个数字丢失。
- 可以直接对所有待查询数字求和sum,然后用1~1000的的数字之和total减去之前求和sum得到的结果即为丢失的数字;
/**
* 1.递归实现1-1000的累加 从最大的开始往下加
*/
public static int sum(int num) {
if (num == 1) {
return 1;
} else
return num + sum(num - 1);
}
/**
* 2.for循环实现1-1000的累加 从最小的开始往上加
*/
public static int sum2(int num) {
int sum = 0;
for (int i = 1; i <= num; i++) {
sum += i;
}
return sum;
}
/**
* 3.利用高斯定理实现1-1000的累加 不往上不往下,首尾成对计算和
*/
public static int sum3(int num) {
/*
* 判断成对的依据By对2求余
*/
int flag = num % 2;
// 如果成对的话,直接利用首尾相加*对数
if (flag == 0) {
// 如果成对的话
int group = num / 2;
return group * (1 + num);
}
// 否则的话 凑够偶数对 减去 那个凑个的数
return sum3(num + 1) - (num + 1);
}
3.int和byte类型的相互转换
// 高位在前,低位在后
public static byte[] int2bytes(int num) {
byte[] result = new byte[4];
result[0] = (byte) ((num >>> 24) & 0xff);
result[1] = (byte) ((num >>> 16) & 0xff);
result[2] = (byte) ((num >>> 8) & 0xff);
result[3] = (byte) ((num >>> 0) & 0xff);
return result;
}
// 高位在前,低位在后
public static int bytes2int(byte[] bytes) {
int result = 0;
if (bytes.length == 4) {
int a = (bytes[0] & 0xff) << 24;
int b = (bytes[1] & 0xff) << 16;
int c = (bytes[2] & 0xff) << 8;
int d = (bytes[3] & 0xff);
result = a | b | c | d;
}
return result;
}