常见位运算题目

在Excel2003中,用A表示第1列,B表示第2列......Z表示第26列,AA表示第27列,AB表示第28列......以此类推。请写出一个函数,输入用字母表示的列号编码,输出它是第几列。

分析:其实这道题就是十进制和26进制之间的转化;

A = 26^0 + 1 = 1

AA = 26 * (26^0 + 1) + 1 = 26 * A + 1

AAA = 26 * [26 * (26^0 + 1)+1] + 1 = 26 * AA + 1

AB = 2*26^0 + 1*26^1 = 26 * A + 2

ABC = 3 * 26^0 + 2 * 26^1 + 1 * 26^2

#include<stdio.h>
#include<string.h>
int Change()
{
  char ch[200];
  scanf("%s",ch);
  int size = strlen(ch);
  int i = 0;
  int ret = 0;
  for(;i<size;i++)
  {
    int tmp = ch[i]-'A';
    if(tmp<0 || tmp >=26)//无效输入
    {
      printf("invalid input\n");
      return -1;
    }
    ret = 26*ret + tmp+1;
  }
  return ret;
}

int main()
{
  while(1)
  {
    int ret = Change();
    printf("ch:%d\n",ret);
  }
  return 0;
}

题目:计算一个二进制数中1的个数

方法一:利用模2除2(负数出现死循环)

while (a)
     {
           if (a % 2 == 1)
           {
                count++;
           }
           a /= 2;
     }

方法二:最右边比特位按位&1 == 1

for (i = 1; i <= 32; i++)
     {
           if ((a & 1) == 1)
           {
                count++;
           }
           a = a >> 1;
     }

方法三:

分析:

 

while (a)
     {
           a = a&(a - 1);
           count++;
     }
     printf("count = %d\n", count);

题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。(领扣:https://leetcode-cn.com/problems/single-number-ii/description/

int singleNumber(int* nums, int numsSize) {
    int i = 0;
    int ret = 0;
    for(;i<32;i++)
    {
        int sum = 0;
        int j = 0;
        for(;j<numsSize;j++)
        {
            sum += (nums[j]>>i) & 1;
        }
        ret |= (sum % 3)<<i;
    }
    return ret;
}

大神解法

int singleNumber(int* nums, int numsSize) {
    int a = 0, b = 0,i=0;
    for(int i = 0;i < numsSize;i++)
    {
        b = (b ^ nums[i]) & ~a;
        a = (a ^ nums[i]) & ~b;
    }
    return b;
}

题目:给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

说明:

  1. 不能更改原数组(假设数组是只读的)。
  2. 只能使用额外的 O(1) 的空间。
  3. 时间复杂度小于 O(n2) 。
  4. 数组中只有一个重复的数字,但它可能不止重复出现一次。

当不考虑条件4的时候:下面代码成立

分析:数组有n+1个元素,题目说明数组包含1和n,所以在这个数组中包含了1到n所以的数字,只是多了一个重复的数字。我们可以利用异或解决此题

1^2^3^3^4^5  ^  (1^2^3^4^5) = 3;最终只有3异或了三次,而其他数异或了两次,所以最终结果为3

int findDuplicate(int* nums, int numsSize) {
	int ret = 0;
	int i = 0;
	for (; i < numsSize; i++){
		ret ^= nums[i];
		ret ^= i;
	}
	return ret;
}

当考虑第四个条件:参考我的上一篇博客:https://blog.youkuaiyun.com/weixin_41318405/article/details/79682281

题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。(领扣:https://leetcode-cn.com/problems/single-number/description/

分析:采用异或算法;两个相同的数异或结果等于0,任何数与0异或等于他本身,异或是半加运算,具有交换律

 int singleNumber(int* nums, int numsSize) {
    int ret = 0;
    int i = 0;
    for(;i<numsSize;i++)
    {
        ret = ret^nums[i];
    }
    return ret;
}

题目:给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

分析:首先所以数字异或得到一个混合结构ret,然后找ret二进制第一次出现1的位置(这个位置代表,是两个不同的数异或得到的结果)所以,利用此位置为1,吧数组分成两部分,一部分是在该位置为0,另外一部分是在该位置为1,当然这两个数肯定会出现在不同的部分,然后利用上题思想,求得两个数 

int* singleNumber(int* nums, int numsSize) {
	int arr[2] = { 0 };
	int ret = 0;
	int i = 0;
	for (; i<numsSize; i++)
	{
		ret ^= nums[i];
	}
	for (i = 0; i<32; i++)
	{
		if (((ret >> i) & 1) == 1)
			break;
	}
	int j = 0;
	for (; j<numsSize; j++)
	{
		if ((nums[j] >> i) &1== 1)
			arr[0] ^= nums[j];
		else
			arr[1] ^= nums[j];
	}
	return arr;
}

题目:给定两个字符串 s 和 t,它们只包含小写字母。

字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。

请找出在 t 中被添加的字母。

char findTheDifference(char* s, char* t) {
    char ret = 0;
    for(;*s != '\0';s++)
        ret ^= *s;
    for(;*t != '\0';t++)
        ret ^= *t;
    return ret;
}

相关题目:

(1)N+1块相同容量的硬盘,其中N块用来存储数据,剩余1块来存储N块硬盘的数据备份,假设同一时间最多一块硬盘有故障,那么该怎么存储数据

答案:异或存储,当其中一块坏了,直接用异或其他好的,结果就是有故障的哪一个

(2)用一条语句判断一个整数是不是2的整数次方

分析:一个整数如果是2的整数次方,那么该整数的二进制只有一个1比特位为1,所以我们可以让这个整数按位与该整数减1的结果,最终结果如果为0,那么就是2的整数次方(和上述题中找二进制中1的个数方法三一样的思想)

(3)输入两个整数m和n,计算需要改变m的二进制比特位多少位,才能得到n

分析:1. 两个数异或。  2. 找异或后结果1出现的次数

(4)把一个整数减1之后在和原来的整数按位与运算,得到的结果相当于吧该整数最右边的二进制数为1的位置改为0.

### Java位运算练习题及相关解析 #### 一、基础知识回顾 Java中的位运算是基于二进制数的操作,主要包括按位与(&)、按位或(|)、按位异或(^)、按位取反(~),以及左移(<<)和右移(>>)操作。这些运算符可以直接作用于整型变量的每一位[^3]。 以下是常见位运算符及其功能: - **& (按位与)**:两个相应位都为1时结果才为1。 - **| (按位或)**:只要有一个相应的位为1,则结果就为1。 - **^ (按位异或)**:当两位不同时结果为1;相同时结果为0。 - **~ (按位取反)**:将所有的0变为1,所有的1变为0。 - **<< (左移)**:向左移动指定的位数,在低位补零。 - **>> (带符号右移)**:向右移动指定的位数,高位由原数值的符号位填充。 - **>>> (无符号右移)**:无论正负数,高位均用0填充。 --- #### 二、典型练习题及解析 ##### 1. 判断奇偶性 编写一个程序,利用位运算判断给定的一个整数是否为奇数。 ```java public class OddEvenCheck { public static boolean isOdd(int num) { return (num & 1) != 0; } public static void main(String[] args) { int number = 7; System.out.println(isOdd(number)); // 输出 true } } ``` **解析**: 通过`num & 1`可以提取最低有效位(LSB)。如果LSB为1,则该数为奇数;否则为偶数。 --- ##### 2. 计算二进制中1的数量 写一段代码计算某个整数的二进制表示中有多少个1。 ```java public class CountBits { public static int countOnes(int n) { int count = 0; while (n != 0) { count += (n & 1); n >>= 1; // 右移一位 } return count; } public static void main(String[] args) { int number = 9; // 二进制形式为 1001 System.out.println(countOnes(number)); // 输出 2 } } ``` **解析**: 每次取出最右侧的一位并累加到计数器中,随后将整个数字右移一位直到其值为0为止。 --- ##### 3. 实现交换两数而不借助额外空间 尝试仅使用位运算完成两个整数之间的互换。 ```java public class SwapNumbers { public static void swapWithoutTemp(int a, int b) { System.out.println("Before swapping: a=" + a + ", b=" + b); a ^= b; // 步骤1 b ^= a; // 步骤2 a ^= b; // 步骤3 System.out.println("After swapping: a=" + a + ", b=" + b); } public static void main(String[] args) { swapWithoutTemp(5, 8); // Before: a=5,b=8 After: a=8,b=5 } } ``` **解析**: 此方法依赖XOR特性来达到无需临时存储即可交换的目的。具体原理如下: 假设初始状态a=x,y=b=y; 执行三次XOR之后得到最终的结果即完成了两者位置上的调换过程。 --- ##### 4. 左移实现乘法 创建函数验证能否通过简单的左移代替特定倍率下的乘积运算。 ```java public class MultiplyByShifts { public static int multiplyByPowerOfTwo(int value, int power) { return value << power; } public static void main(String[] args) { int result = multiplyByPowerOfTwo(3, 2); // 等价于 3 * 2² = 12 System.out.println(result); // 输出 12 } } ``` **解析**: 对于任何非负整数k来说,把某数x左移k位相当于将其乘以2ᵏ次方。 --- ##### 5. 使用掩码设置/清除特定位 定义一组宏用于快速修改目标字节串内的某些固定范围标志位的状态。 ```java // 假设我们想控制第N位开关 final int MASK_SET_BIT_NTH = 1 << N; // 设置第N位 final int MASK_CLEAR_BIT_NTH = ~(1 << N); // 清除第N位 int applyMask(int originalValue, boolean setFlag) { if(setFlag){ return originalValue | MASK_SET_BIT_NTH ; }else{ return originalValue & MASK_CLEAR_BIT_NTH ; } } System.out.println(Integer.toBinaryString(applyMask(0b1111_0000 ,true))); // 结果应显示新增激活标记后的模式 System.out.println(Integer.toBinaryString(applyMask(0b1111_0000 ,false))); // 对照组则呈现未改变前原始样式 ``` **解析**: 这里展示了如何构建合适的mask并通过逻辑组合调整单一比特域的行为方式。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_41318405

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值