An array A[1…n] contains all the integers from 0 to n except for one number which is missing. In this problem, we cannot access an entire integer in A with a single operation. The elements of A are represented in binary, and the only operation we can use to access them is “fetch the jth bit of A[i]”, which takes constant time. Write code to find the missing integer. Can you do it in O(n) time?
数组A[1…n]包含0到n的所有整数,但有一个整数丢失了。在这个问题中, 我们不能直接通过A[i]取得数组中的第i个数。数组A被表示成二进制, 也就是一串的0/1字符,而我们唯一能使用的操作只有“取得A[i]中的第j位”, 这个操作只需要花费常数时间。写程序找出丢失的整数,你能使程序的时间复杂度是O(n)吗?
首先,在这个问题中,明确我们唯一能使用的操作是fetch(a, i, j)即: 取得a[i]中的第j位。它是提供给我们的操作,怎么实现的不用去理它, 而我们要利用它来解决这个问题,并且在我们的程序中,不能使用a[i]这样的操作。
如果我们不能直接使用a[i],那么我们能利用fetch函数来获得a[i]吗?回答是可以。 数组a中每个元素是一个整型数,所以只要每次取出32位,再计算出它的值即可。
代码如下:
int get(int a[], int i){
int ret = 0;
for(int j=31; j>=0; --j)
ret = (ret << 1) | fetch(a, i, j);
return ret;
}
我们已经通过get(a, i)来取得a[i]的值了,这样一来,我们只需要开一个bool数组, 把出现过的整数标记为true,即可找出丢失的那个整数。
代码如下:
int missing(int a[], int n){
bool *b = new bool[n+1];
memset(b, false, (n+1)*sizeof(bool));
for(int i=0; i<n; ++i)
b[get(a, i)] = true;
for(int i=0; i<n+1; ++i){
if(!b[i]) return i;
}
delete[] b;
}
我们把问题再变难一点点,如果我们能取到的只是数组a中的第j位,即有函数fetch(a, j), 而不是取到a[i]中的第j位,那又应该怎么做呢。其实也很简单, 计算a[i]需要取出a[i]中的第31位到第0位(共32位),对应到整个数组上, 就是数组从头开始数起,取出第
32*i+31
位到第32*i
位,代码如下:int get1(int a[], int i){
int ret = 0;
int base = 32*i;
for(int j=base+31; j>=base; --j)
ret = (ret << 1) | fetch1(a, j);
return ret;
}
public static int fetch(int a[],int i,int j){ return (a[i]>>j)&1; } public static int get(int[] a ,int i){ int result = 0 ; for(int j=31;j>=0;--j){ result = result<<1|fetch(a,i,j); } return result ; }
https://github.com/careercup/CtCI-6th-Edition/tree/master/Java/Ch%2017.%20Hard/Q17_04_Missing_Number
public class BitInteger {
public static int INTEGER_SIZE;
private boolean[] bits;
public BitInteger() {
bits = new boolean[INTEGER_SIZE];
}
/* Creates a number equal to given value. Takes time proportional
* to INTEGER_SIZE. */
public BitInteger(int value){
bits = new boolean[INTEGER_SIZE];
for (int j = 0; j < INTEGER_SIZE; j++){
if (((value >> j) & 1) == 1) bits[INTEGER_SIZE - 1 - j] = true;
else bits[INTEGER_SIZE - 1 - j] = false;
}
}
/** Returns k-th most-significant bit. */
public int fetch(int k){
if (bits[k]) return 1;
else return 0;
}
/** Sets k-th most-significant bit. */
public void set(int k, int bitValue){
if (bitValue == 0 ) bits[k] = false;
else bits[k] = true;
}
/** Sets k-th most-significant bit. */
public void set(int k, char bitValue){
if (bitValue == '0' ) bits[k] = false;
else bits[k] = true;
}
/** Sets k-th most-significant bit. */
public void set(int k, boolean bitValue){
bits[k] = bitValue;
}
public void swapValues(BitInteger number) {
for (int i = 0; i < INTEGER_SIZE; i++) {
int temp = number.fetch(i);
number.set(i, this.fetch(i));
this.set(i, temp);
}
}
public int toInt() {
int number = 0;
for (int j = INTEGER_SIZE - 1; j >= 0; j--){
number = number | fetch(j);
if (j > 0) {
number = number << 1;
}
}
return number;
}
}
/* Create a random array of numbers from 0 to n, but skip 'missing' */
public static ArrayList<BitInteger> initialize(int n, int missing) {
BitInteger.INTEGER_SIZE = Integer.toBinaryString(n).length();
ArrayList<BitInteger> array = new ArrayList<BitInteger>();
for (int i = 1; i <= n; i++) {
array.add(new BitInteger(i == missing ? 0 : i));
}
// Shuffle the array once.
for (int i = 0; i < n; i++){
int rand = i + (int) (Math.random() * (n-i));
array.get(i).swapValues(array.get(rand));
}
return array;
}
public static int findMissing(ArrayList<BitInteger> array) {
return findMissing(array, BitInteger.INTEGER_SIZE - 1);
}
private static int findMissing(ArrayList<BitInteger> input, int column) {
if (column < 0) { // Base case and error condition
return 0;
}
ArrayList<BitInteger> oneBits = new ArrayList<BitInteger>(input.size()/2);
ArrayList<BitInteger> zeroBits = new ArrayList<BitInteger>(input.size()/2);
for (BitInteger t : input) {
if (t.fetch(column) == 0) {
zeroBits.add(t);
} else {
oneBits.add(t);
}
}
if (zeroBits.size() <= oneBits.size()) {
int v = findMissing(zeroBits, column - 1);
System.out.print("0");
return (v << 1) | 0;
} else {
int v = findMissing(oneBits, column - 1);
System.out.print("1");
return (v << 1) | 1;
}
}