【LeetCode】762. Prime Number of Set Bits in Binary Representation

版权声明:--(●'◡'●)-- --(●ˇ∀ˇ●)-- https://blog.csdn.net/qq_36032149/article/details/85238679

Prime Number of Set Bits in Binary Representation

一堆题放一块太挤了,还是分开放=.=,也能写得详细一点

Problem

求[L,R]这个闭区间内的数字 二进制表示形式 1的个数 为素数 的数量

Example

L = 6, R = 10
6(0101),1的个数为2,2是素数 +1
7(1001),1的个数为2, 2是素数 +1
8(1000),1个1,1不是素数
9(1001),2个1,2是素数 +1
10(1010),2个1,2是素数 +1
一共4个1 ,输出为4

Solution

思路1
暴力解法,遍历L到R,计算每个数1的个数,判断这个数是否为素数

class Solution {
    public int countPrimeSetBits(int L, int R) {
        int res = 0;
        for (int i = L; i <= R; i++) {
            int ct = counter(i);//计算1的个数
            if (isPrime(ct)) {//判断是否为素数
            	res++;
            }
        }
        return res;
    }
    //计算1的个数
    int counter(int num) {
    	int c = 0;
    	while (num != 0) {
    		num >>= 1;
    		//if (num & 1 == 1)
    		//	  c++;
    		c += num & 1;//可简写为这样
    	}
    	return 1;
    }
	//判断是否为素数
	public boolean isPrime(int num) {
		int tmp = (int) Math.sqrt(num);//获取平方根
		for (int i = 2; i <= tmp; i++) {
			if (num % i == 0) {
				return false;
			}
		}
		return true;
    }
}

思路2
可以从计算素数的地方优化,也可以从计算1的个数的地方进行优化
1.计算素数这个,因为题目条件范围数字最大为106 大概220次方,也就是最多19个1,可以把1-19的素数都枚举出来(2,3,5,7,11,13,17,19)
2.计算1的个数,java的Integer.bitCount(int)函数(暂时没看懂这个算法),用O(1)的时间就算出来了=.=!,有空了解一下

class Solution {
    public int countPrimeSetBits(int L, int R) {
        int res = 0;
        for (int i = L; i <= R; i++) {
            int ct = counter(i);//计算1的个数
            if (isPrime(ct)) {//判断是否为素数
            	res++;
            }
        }
        return res;
    }
    //计算1的个数(Integer类自带的一个O(1)的解法,万万想不到=.=!)
    int counter(int num){
    	return Integer.bitCount(num);
    }
	public boolean isPrime(int num) {
		return (num == 2 || num == 3 || num == 5 || num == 7 || num == 11 || num ==13 || num == 17 || num == 19);
	}

思路3
下面是自己的解法(用Integer.bitCount()替换了原先while求1个数的算法,LeetCode运行时间从20ms左右,到了11ms)时间复杂度为O(n)
只是判断素数那里和答案不一样

    //20以内的素数表
    private int[] primers = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1};
    public int countPrimeSetBits(int L, int R) {
        int res = 0;
        while (L <= R) {
            res += primers[Integer.bitCount(L++)];
        }
        return res;
    }

思路4
用 分治 试了试,不过也是10-13毫秒左右,时间上并没什么太大的突破
不过每次递归实际上只计算了1个数。。相当于把水平的for循环迭代改为垂直的递归,白白多了log(n)的空间占用。

    //20以内的素数表
    private int[] primers = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1};
    public int countPrimeSetBits(int L, int R) {
        if (L <= R) {
            int M = (L + R) / 2;
            int m = primers[Integer.bitCount(M)];//求解中间
            int a = countPrimeSetBits(L, M - 1);//递归求解左边
            int b = countPrimeSetBits(M + 1, R);//递归求解右边
            return a + b + m;//把左中右的加起来
        }
        return 0;
    }

接下来就是大佬的show time了
运算最快的人的答案
大佬用位运算把素数存在了一个整数中。。
然后用这个数右移,比如(…101100)右移2,3,5等素数位,最低为一定为1

	public int countPrimeSetBits(int L, int R) {
		int primes = 0;
		primes += 1<<2;
		primes += 1<<3;
		primes += 1<<5;
		primes += 1<<7;
		primes += 1<<11;
		primes += 1<<13;
		primes += 1<<17;
		primes += 1<<19;
		primes += 1<<23;
		primes += 1<<29;
		int ans =0;
		for(int i=L; i<=R; i++){
		    if(((primes >> Integer.bitCount(i)) & 1) == 1){
		        ans++;
		    }
		}
		return ans;        
	}

可以简单优化一下
把那个数字直接算出来(0b1010_0010_1000_1010_1100),16进制0xA28AC

	public int countPrimeSetBits(int L, int R) {
		int ans =0;
		while (L <= R) {
	        ans += (0xA28AC >> Integer.bitCount(i)) & 1;
		}
		return ans;        
	}

猜你喜欢

转载自blog.csdn.net/qq_36032149/article/details/85238679