Topic 5.3 Given a positive integer, print the next smallest and the next largest number that have the same number of 1 bits in their binary representation.
方法1:
Brute Force Approach: count the number of 1s in n, and then increment (or decrement) until you find a number with the same number of 1s.
方法2:
1)Find_Next:把右边有1的第一个0—>1,把该0后面的所有1移到最低位。Flip the rightmost zero,say p, which has a one next to it. Count how many ones (c) are to the right of p, clear all the bits below p, and add c-1 ones from the lowest bit.
2) Find_Previous: Compute c0 and c1, c1 is the number of trailing ones, c0 is the size of the block of zeros immediately to the left of the trailing ones. Flip the rightmost non-trailing one to zero, at position p=c1+c0, clear all bits to the right of bit p. Insert c1+1o ones immediately to the right of p.
方法3:
Arithmetic Approach.是在方法2的基础上更直接的利用数学做了简化。最后简化为两步
Next: returnn+ (1<< c0) + (1<< (c1- 1))-1;
Pre: returnn- (1<< c1) - (1<< (c0- 1))+1;
特别注意:
一开始给定一个int值,是32位的,有一些数是没有Next或Previous的。(int有符号,第32位是符号位)
1) 第31位为1,那么它的next是1000…0,实际是-1;对于所有010…,0110…, 01110…,比它大的合要求的都不存在。
2) 对于形如11100…00的整数,是负数,比它小的合要求的不存在,比它大且1个数相同的是00…0111。
public class c5_3 {
public static int countOnes(int i) {
int count = 0;
while (i > 0) {//神奇的方法
if ((i & 1) == 1) {
count++;
}
i = i >> 1;
}
return count;
}
public static int countZeros(int i) {
return 32 - countOnes(i);
}
//要检查是否有有效的下一个和上一个
public static boolean hasValidNext(int i) {
if (i == 0) {
return false;
}
int count = 0;//太神奇了!!!count返回的是从最右边数起,连续的0+连续的1,符合特别注意第一条
while ((i & 1) == 0) {
i >>= 1;
count++;
}
while ((i & 1) == 1) {
i >>= 1;
count++;
}
if (count == 31) {
return false;
}
return true;
}
public static boolean hasValidPrev(int i) {
while ((i & 1) == 1) {
i >>= 1;
}
if (i == 0) {
return false;
}
return true;
}
public static int getNext1(int i) {//蛮力法
if (!hasValidNext(i)) {
return -1;
}
int num_ones = countOnes(i);
i++;
while (countOnes(i) != num_ones) {
i++;
}
return i;
}
public static int getPrev1(int i) {//蛮力法
if (!hasValidPrev(i)) {
return -1;
}
int num_ones = countOnes(i);
i--;
while (countOnes(i) != num_ones) {
i--;
}
return i;
}
public static int getNext2(int n) {
int c = n;
int c0 = 0;
int c1 = 0;
while (((c & 1) == 0) && (c != 0)) {
c0++;
c >>= 1;
}//解决了最右边所有的0,0的个数在c0里
while ((c & 1) == 1) {
c1++;
c >>= 1;
}//解决了最右边0前面所有的1,1的个数在c1里
/* If c is 0, then n is a sequence of 1s followed by a sequence of 0s. This is already the biggest
* number with c1 ones. Return error.
*/
if (c0 + c1 == 31 || c0 + c1 == 0) {
return -1;
}
int pos = c0 + c1;
n |= (1 << pos); // Flip right-most non-trailing zero
// Clear all bits to the right of pos.
n &= ~((1 << pos) - 1);
n |= (1 << (c1 - 1)) - 1;
return n;
}
public static int getPrev2(int n) {
int c = n;
int c0 = 0;
int c1 = 0;
while ((c & 1) == 1) {
c1++;
c >>= 1;
}
/* If temp is 0, then the number is a sequence of 0s followed by a sequence of 1s. This is already
* the smallest number with c1 ones. Return -1 for an error.
*/
if (c == 0) {
return -1;
}
while (((c & 1) == 0) && (c != 0)) {
c0++;
c >>= 1;
}
int p = c0 + c1;
n &= ((~0) << (p + 1)); // clears from bit p onwards (to the right)
int mask = (1 << (c1 + 1)) - 1; // Sequence of (c1+1) ones
n |= mask << (c0 - 1);
return n;
}
public static void binPrint(int i) {
System.out.println(i + ": " + Integer.toBinaryString(i));
}
public static void main(String[] args) {
int i = 15;
int p1 = getPrev2(i);
int n1 = getNext2(i);
binPrint(i);
binPrint(p1);
binPrint(n1);
System.out.println("");
}
}
//结果
15: 1111
-1: 11111111111111111111111111111111
23: 10111