9.5位操作(三)——给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数

/**

* 功能:给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数。

* (一个略大一个略小。)

*/

三种方法:

方法一:蛮力法

方法二:位操作法

<span style="white-space:pre">	</span>/**
	 * 方法:位操作法
	 * 思路:获取后一个较大的数
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将最右边、非拖尾0变为1,其位置为p=c1+c0。
	 * 		3)将位p右边的所有位清零。
	 * 		4)在紧邻位置p的右方,插入c1-1个1。
	 * @param n
	 * @return
	 */
	public static int getNext(int n){
		int c=n;
		int c0=0;
		int c1=0;

		while((c&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}

		while((c&1)==1){
			c1++;
			c>>=1;
		}

		if(c0+c1==31||c0+c1==0)//c0+c1+1=32,1表示p所在位。
			return -1;

		int p=c0+c1;//最右边处,非拖尾0的位置。
		n|=(1<<p);//翻转0为1
		n&=~((1<<p)-1);//将p右边的所有位清零
		n|=(1<<(c1-1))-1;//在右边填入(c1-1)个1

		return n;
	}

	/**
	 * 思路:获取前一个较小的数
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将最右边、非拖尾1变为0,其位置为p=c1+c0。
	 * 		3)将位p右边的所有位清零。
	 * 		4)在紧邻位置p的右方,插入c1+1个1。
	 * 		注意:步骤2和3可以合并。
	 * @param n
	 * @return
	 */
	public static int getPrev(int n){
		int c=n;
		int c0=0;
		int c1=0;

		while((c&1)==1){
			c1++;
			c>>=1;
		}

		if(c==0)
			return -1;//错误检查!!!全为1时,无法找到

		while((c&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}

		int p=c0+c1;
		n&=~((1<<(p+1))-1);//将最右边、非拖尾1变为0,其位置为p=c1+c0;将位p右边的所有位清零。
		int mask=(1<<(c1+1))-1;//在紧邻(!!!)位置p的右方,插入c1+1个1。
		n|=mask<<(c0-1);

		return n;
	}

方法三:算术法

<span style="white-space:pre">	</span>/**
	 * 方法:算术法
	 * 思路:获取后一个较大的数,重新表述问题
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将p位置1。
	 * 		3)将位p右边的所有位清零。
	 * 		4)在紧邻位置p的右方,插入c1-1个1。
	 * 步骤2,3有一种快速做法,将拖尾0置为1(得到p个拖尾1),然后再加1。加1后,所有拖尾1都会翻转,最终位p变为1,后边跟p个0.
	 * @param n
	 * @return
	 */
	public static int getNextArith(int n){
		int c=n;
		int c0=0;
		int c1=1;

		while((c0&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}

		while((c1&1)==1){
			c1++;
			c>>=1;
		}

		if(c0+c1==31||c0+c1==0)
			return -1;

		//将拖尾0置1,得到p个拖尾1
		n|=(1<<c0)-1;
		//先将p个1清零,然后位p改为1
		n+=1;
		//在右边填入(c1-1)个1
		n|=(1<<(c1-1))-1;

		return n;
	}
	/**
	 * 方法:算术法
	 * 思路:获取前一个较小的数,重新表述问题
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将p位清零。
	 * 		3)将位p右边的所有位置1。
	 * 		4)将位0到位c0-1清零。
	 * @param n
	 * @return
	 */
	public static int getPrevArith(int n){
		int c=n;
		int c0=0;
		int c1=0;

		while((c&1)==1){
			c1++;
			c>>=1;
		}

		while((c&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}

		if(c==0)
			return -1;//错误检查!!!全为1时,无法找到

		n-=(1<<c1)-1;//清除拖尾1,此时p位为1,后面全部为零
		n-=1;//将p为置0,后面所有位置置1
		n&=~(1<<(c0-1)-1);//将最后边置c0-1个0

		return n;
	}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 18:55:19

9.5位操作(三)——给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数的相关文章

大小最接近的那两个数(位操作)

主要是熟悉位操作,寻找一个数二进制1位相同,且大小最相近的数. //题目描述 // //有一个正整数,请找出其二进制表示中1的个数相同.且大小最接近的那两个数.(一个略大,一个略小) //给定正整数int x,请返回一个vector,代表所求的两个数(小的在前).保证答案存在. //测试样例: //2 //返回:[1, 4] // //思路: //取得略大的数: //c0 是拖尾0的个数,c1是紧邻拖尾0左方连续位为1的个数, p为最右边但非拖尾的0 等于 c0 + c1 //1 把位p置为1

c#编程:给定一个正整数求出是几位数并逆序输出

<span style="color:#FF0000;">第一步:把输入的数字转为字符串n.ToString() 第二步:求出字符串的长度即为正整数的位数 第三步:从后向前逆序输出</span> 附代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; //给一个正整数, //要求:一.求它是几位数,二.逆序打印出各位数字. namespa

一道笔试题-给定一个正整数序列,请尝试将它们重新排列使得排列的结果最大。

问题描述:给定一个正整数序列,请尝试将它们重新排列使得排列的结果最大,例如正整数序列为9,31,35,3,7则最大值为9735331. 思路分析:先将正整数序列转换为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可.根据题目的要求,两个数字m和n排成的数字mn和nm,如果mn<nm,那么我们应该输出nm,也就是m应该排在n的后面,也就是m<n.反之,如果nm<mn,m排在n的前面,n<m.如果mn==mn,m等于n. 比较函数的定义是本解决方案的关键.这道题其实就是希

用JAVA写一个函数,功能如下: 任意给定一组数, 找出任意数相加之后的结果为35(任意设定)的情况

用JAVA写一个函数.功能如下:任意给定一组数,例如{12,60,-8,99,15,35,17,18},找出任意数相加之后的结果为35(任意设定)的情况. 可以递归算法来解: package test1; import java.util.Arrays; public class demo { public static void main(String[] args) { String str = "12,60,-8,99,15,35,17,18,8,10,11,12"; int s

给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。

问题描述:给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果.输入值小于1000.如,输入为10,程序应该输出结果为2.(共有两对质数的和为10,分别为(5,5),(3,7)) 附算法代码: public class PrimeNumber { //判断是否是质数 protected boolean isPrimeNumber(int num){ if(num == 2) return true;//2特殊处理 if(num < 2 || num % 2 == 0) r

给定一个正整数,实现一个方法求出离该整数最近的大于自身的 换位数 &lt;把一个整数各个数位进行全排列&gt;

"""给定一个正整数,实现一个方法求出离该整数最近的大于自身的 换位数 -> 把一个整数各个数位进行全排列""" # 使用 permutations() 方法实现import itertools def full_arrangement(num): my_str = '' my_list = [] permutation = list(itertools.permutations(str(num), len(str(num)))) for

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

/* 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. */ #include<stdio.h> #include<math.h> main() { int n,rs=1; scanf("%d",&n); if(n==2){ printf("1\n"); return 0; } if(n==3){ printf("2\n"); return 0; } whil

给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是: 1,3,4,9,10,12,13,… (该序列实际上就是:3^0,3^1,3^0+3^1,3^2,3^0+3^2,3^1+3^2,3^0+3^1+3^2,…) 请你求出这个序列的第N项的值(用10进制数表示)。 例如,对于k=3,N=100,正确答案应该是9

只有1行,为2个正整数,用一个空格隔开: k N (k.N的含义与上述的问题描述一致,且3≤k≤15,10≤N≤1000). 计算结果,是一个正整数(在所有的测试数据中,结果均不超过2.1*10^9).(整数前不要有空格和其他符号). #include<stdio.h> int n2[1010];long long l1 = 1; long long n, k; long long sm(long long i,long long k) { long long s = 1; int j; fo

编写一个程序找出100~999之间所有的水仙花数

如果一个3位数等于其各位的立方和,称该数为水仙花数. 如,所以407是一个水仙花数,编写一个程序找出100~999之间所有的水仙花数. 1 #include<stdio.h> 2 #include<stdlib.h> 3 //判断水仙花数,是则返回1 4 int isNarcissus(int n); 5 6 int main() 7 { 8 int i; 9 for(i = 100; i < 1000; i++) 10 if(isNarcissus(i)) 11 print