最近在力扣上刷了一道题,不是很难,过来挑战把思路讲出来。
后面给出的示例如下:
接下来将结合个人理解和官方题解(作者:力扣官方题解
链接:https://leetcode.cn/problems/prime-number-of-set-bits-in-binary-representation/solutions/1389365/er-jin-zhi-biao-shi-zhong-zhi-shu-ge-ji-jy35g/
来源:力扣(LeetCode)),介绍两种解题思路。
思路一 数学+位运算
本题有两个关键点:分析出整型数字的二进制形式,以及判断数字的二进制里的1的总数是否为质数。
首先解决第一个关键。将十进制的整型数字转化为二进制。这里有两种思路。第一种是基础思路,就是不断将原数字%2(二进制满二进一,这里判断二进制每一位上是0还是1),判断余数是否为1。
第二种转化二进制思路是用“ n&(n-1) ” 。由于每次n-1就让原来n上最低位的1被消去,n&(n-1)后又成功将消去位以右的二进制位,将它们都化为0,实现了每次消去二进制最右边一个1的功能;最终实现统计位1的个数。用例子解释如下:
再解决第二个关键:判断质数。判断质数,有两种思路:
- 利用一个i 变量遍历从2到被求数之间的数并与之相除,没有出现整除即为质数。
- 利用i 变量遍历从2到sqrt(被求数)之间的数并与之相除,没有出现整除即为质数。
第一种老生常谈且基础,运用第二种思路写出来的代码更加高效。
综上,可以写出程序如下:
int isPrime(int left, int (* Func_count)(int))
{
int num = (*Func_count)(left);//num接受对一个二进制数里1的计数
if (num < 2)
return 0;//0或1都不是质数
else {
for (int i = 2; i * i <= num; i++)
//判断质数:用2至根号下num之间的数字除原数,如果出现余数为0,则不是质数
{
if (num % i == 0)
return 0;
}
}
return 1;//排除上述两只情况,其他都是质数
}
int Func_count(int num)//基础方法,将原数转换为二进制数,并统计1的个数
{
int count = 0;
while (num != 0)
{
if (num % 2 == 1)
count++;
num /= 2;
}
return count;
}
int main()
{
int left = 0, right = 0;
int sum = 0;
scanf("%d %d", &left, &right);
while(left<=right)
{
if (isPrime(left, Func_count))//0-不是质数,1-是质数
sum++;
left++;
}
printf("%d\n", sum);
return 0;
}
这个程序主要是思路比较清晰。
思路二 质数判断优化-按位与
按位与&:
在两个数都为int型的大前提下,判断两个数的二进制(补码的形式)每位的01相同情况。只有对应的两个二进制位都为1时,才得1;否则为0 。
比如,判断 10&3 的结果,思路如下:
根据按位与的功能,我们再来思考这道题。
题里有提到左右两个数的取值范围最高到10^6为止,而10^6 < 2^20,可推知本题判断的“二进制位1的总计数”的质数范围也就在0~20之间,20内的质数一共有:2,3,5,7,11,13,17,19。所以我们可以将它们储存在一个新的二进制里——
mask=665772=10100010100010101100
假设left至right之间有一个数x,它的二进制位1的总数为c,就可以用(mask)&(2^c)的方式来判断c在二进制中的位置是否是在质数的位置:
int Func_count(int num)//二进制位1统计的第二种方法
{
int count = 0;
while (num)
{
num &= num - 1;
count++;
}
return count;
}
int main()
{
int left = 0, right = 0, sum = 0;
scanf("%d %d", &left, &right);
while (left <= right)
{
if (1 << Func_count(left) & 665772)
//先将1左移统计数count的位数,即将返回值放在二进制的相应位数上
sum++;
left++;
}
printf("sum = %d\n", sum);
return 0;
}
总结
这道题里,对于判断二进制位1的两种方法,操作符的方法还需多多回顾,以便于掌握。同时对于质数判断的优化方法也要多加理解,一方面能开拓思路,另一方面可以加深对本题的认识。