常见位运算题目

在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.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

weixin_41318405

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

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

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

打赏作者

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

抵扣说明:

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

余额充值