利用操作符解题的精彩瞬间

下面是链接为了解释练习2的并且还有与操作符相关的知识。 

C语言与操作符相关的经典例题-CSDN博客

操作符详解(上)-CSDN博客

操作符详解(下)-CSDN博客

目录

练习1:在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。

练习2:两个整数二进制位不同个数

练习3:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列


前言:有些题目可能我们想破脑袋也不知道怎么写,但是如果用一些看似奇怪的方法去写,就能有一种柳暗花明又一村的感觉。虽然这些代码是那些大牛想到的,但是只要我们坚持看这些大牛的代码,我们总可以多学到一点。(个人感想,可忽略。

步入正题:

练习1:在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。

这个题目是关键就是找到那个单独的数字。如果我们能想到用按位异或(^)的方法就比较简单了。

解题的知识储备:0 ^ n = n     n ^ n = 0   。

思路:我们可以先定义一个变量等于0,用它来异或数组里的数。由于0 ^ n = n,所以这个变量不影响最终的求值。(当然这一步如果简化就是把这个变量初始化为数组的第一个元素,而异或开始的是用第二个元素。)用循环产生这些数组的元素,当我们把它们全部异或到一起时,就可以用到n ^ n = 0,这个最终剩下的就是那个单独的数字,也就是我们要找的那个数。

上面这个就是原理图 。之所以可以这样做,是因为异或也满足交换律。

#include <stdio.h>
int FindNumber(int* p, int sz)
{
	int i = 0;
	int flag = 0;
	for (i = 0; i < sz; i++)
	{
		flag ^= *(p + i);
	}
	return flag;
}
int main()
{
	int arr[] = { 1,2,3,4,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = FindNumber(arr, sz);//因为要遍历数组,所以需要数组和数组的元素
	printf("%d\n", ret);
	return 0;
}
#include <stdio.h>
int FindNumber(int* p, int sz)
{
	int i = 0;
	int flag = 1;
	for (i = 1; i < sz; i++)
	{
		flag ^= *(p + i);
	}
	return flag;
}
int main()
{
	int arr[] = { 1,2,3,4,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = FindNumber(arr, sz);//因为要遍历数组,所以需要数组和数组的元素
	printf("%d\n", ret);
	return 0;
}

 第二个代码是用括号内(上面分析的时候,我用绿色标记出来)写法的。

代码演示:

练习2:两个整数二进制位不同个数

两个整数二进制位不同个数_牛客题霸_牛客网

题目:

思路:题目是要求输入的两个数,二进制中又多少个比特位不相同。既然是让我们求两个数的二进制位不同个数,这里我们应该就可以联想到一个操作符:按位异或(^),相同的二进制位取0,不同的二进制位取1。我们就可以把这两个数按位异或存放到第三个数中,既然不同的二进制位是1,那么只要我们把这个1的个数统计出来了,也就意味着求出来二进制中不同位的个数了。

#include <stdio.h>
int Num(int c)
{
    int count = 0;
    while(c)
    {
        c = c & (c-1);//这一步如果看不懂的话,可以去看我前面的那一篇关于操作符的文章,我将链接放到文章的最前面了
        count++;
    }
    return count;
}
int main()
{
    int a = 0;
    int b = 0;
    scanf("%d%d",&a,&b);
    int c = a ^ b;
    int ret = Num(c);//求二进制中一的个数(用函数来实现)
    printf("%d\n",ret);
    return 0;
}

之所以用函数的方法,是因为不想让这个主函数看起来很长,这样会影响代码的美观。

按位异或的思想其实就是在找不同,如果想要找到不同的地方,就可以使用按位异或的方法。

这个就类似题眼。

练习3:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列

这个题目其实就是在变相的问一个整数二进制的0和1的个数并且按照奇偶打印出来。因为一个整数的二进制位要么是0,要么是1。那么我们怎么知道这个整数的二进制位是0还是1呢?这里就可以用按位与(&)来计算,当我们按位与上一个1是,如果这个位是0,那么最终的结果就是0;如果这个位是1,那么最终的结果就是1。这是第一位的结果,我们要的是32个位,那么就循环32次。我们只要分奇偶来按位与,并且输出就可以了。接下来,就是要分奇偶来讨论了。讨论奇数的时候怎么循环?偶数的时候怎么循环?我就用画图来描述:

根据8位,我们就可以推出32位的循环结果。如果i从0开始,那么结束的位置就都要减1。因为开始是0。

 代码演示:

#include <stdio.h>
void Get(int n)
{
	int i = 0;
	printf("奇数位:");
	for (i = 0; i < 31; i += 2)//打印奇数位
	{
		if (((n >> i) & 1) == 1)
		{
			printf("%d ", 1);
		}
		else
		{
			printf("%d ", 0);
		}
	}
	printf("\n");
	printf("偶数位:");
	for (i = 1; i < 32; i += 2)//打印偶数位
	{
		if (((n >> i) & 1) == 1)
		{
			printf("%d ", 1);
		}
		else
		{
			printf("%d ", 0);
		}
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	Get(n);
	return 0;
}

其实这个还可以简化一点,既然 ((n >> i) & 1)的结果是1,就打印1;结果是0,就打印0。那么我们就直接把这个表达式当作是printf的参数就更好了。

#include <stdio.h>
void Get(int n)
{
	int i = 0;
	printf("奇数位:");
	for (i = 0; i < 31; i += 2)
	{
		printf("%d ", (n >> i) & 1);
	}
	printf("\n");
	printf("偶数位:");
	for (i = 1; i < 32; i += 2)
	{
		printf("%d ", (n >> i) & 1);
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	Get(n);
	return 0;
}

但是这里有的小伙伴可能会将1的位数给移动,因为移动1的位数相对比较简单。但是这个题目狡猾就狡猾在这里。你移动了那个位数之后,虽然比较出来的结果是1,但是它的权重变了,不再是2的0次方,而是2的1次方,2的2次方等等。这样写出来的程序就输出的不是1了。

#include <stdio.h>
void Get(int n)
{
	int i = 0;
	printf("奇数位:");
	for (i = 0; i < 31; i += 2)//打印奇数位
	{
		printf("%d ", n & (1 << i));
	}
	printf("\n");
	printf("偶数位:");
	for (i = 1; i < 32; i += 2)//打印偶数位
	{
		printf("%d ", n & (1 << i));
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	Get(n);
	return 0;
}

我们输入的是7,输出的却是1,2,4,但是我们会发现两者之和相等。这就是因为权重的问题。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我要学编程(ಥ_ಥ)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值