5.3

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:

1Find_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位的,有一些数是没有NextPrevious的。(int有符号,第32位是符号位)

1)  31位为1,那么它的next1000…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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值