[leetCode 丶 20241122] 3233. 统计不是特殊数字的数字数量

原题: 3233.统计不是特殊数字的数字数量


描述:

给你两个 *正整数 lr。对于任何数字 xx 的所有正因数(除了 x 本身)被称为 x真因数

如果一个数字恰好仅有两个 真因数,则称该数字为 特殊数字。例如:

  • 数字 4 是 特殊数字,因为它的真因数为 1 和 2。
  • 数字 6 不是 特殊数字,因为它的真因数为 1、2 和 3。
    返回区间 *[l, r]不是 特殊数字 的数字数量。

示例 1

输入: l = 5, r = 7
输出: 3
解释:
区间 [5, 7] 内不存在特殊数字。

示例 2

输入: l = 4, r = 16
输出: 11
解释:
区间 [4, 16] 内的特殊数字为 4 和 9。

提示

  • 1 <= 1 <= r <= 10^9

个人版答案

执行用时: 76 ms 执行内存消耗: 40 M

class Solution {
    public int nonSpecialCount(int l, int r) {
        int start = (int) Math.ceil(Math.sqrt(l));
        int end = (int) Math.floor(Math.sqrt(r));
        int c = 0;
      
        for (int i = start; i <= end; i++) {
            if (i * i >= l && i * i <= r) {
                if (isPrime(i)) {
                    c++;
                }
            }
        }

        return r - l + 1 - c;
    }

    public static boolean isPrime(int num) {
        if (num <= 1) {
            return false;
        }
        if (num == 2) {
            return true;
        }
        if (num % 2 == 0) {
            return false;
        }
        for (int i = 3; i <= Math.sqrt(num); i += 2) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }
}

优秀解法

执行耗时: 2 ms

class Solution {
    private static final List<Integer> primePower = new ArrayList<>();
    private static final int n;

    static {
        // 方法一:埃式筛
        int MAX = 31623;
        boolean[] np = new boolean[MAX + 1];
        for (int i = 2; i <= MAX; i++) {
            if (!np[i]) {
                // 质数
                primePower.add(i * i);
                int a;
                for (int j = i; (a = i * j) <= MAX; j++) {
                    np[a] = true;
                }
            }
        }
        n = primePower.size();
    }

    public int nonSpecialCount(int l, int r) {
        // 1)  >=6 的偶数一定不是特殊数字 至少有1,2 和 n/2 3个真因数
        // 2)  质数一定不是特殊数字, 只有1个真因数
        // 1 2 3 4 5 中  只有 4 是 特殊数字(2个真因素1, 2)
        // n 除了1以外只有一个真因子 a * a = n  a > 1  且 a是质数
        // 问题转化为[l,r]内不是质数平方数的个数
        // a * a >=l
        int t = binarySearch(-1, n, r + 1) - binarySearch(-1, n, l);
        return r - l + 1 - t;
    }

    // 返回 primeArr中 平方数>= t 的最小下标
    private int binarySearch(int l, int r, int t) {
        while (l + 1 < r) {
            int mid = l + (r - l) / 2;
            if (primePower.get(mid) >= t) {
                r = mid;
            } else {
                l = mid;
            }
        }
        return r;
    }
}

个人解题思路与优秀答案解析

题目分析及个人版思路

  1. 没看懂...再看一眼
  2. 这说的是什么玩意儿?
  3. 嗷... 就是质数平方数在区间呗...说人话真难.
  4. 3容易理解不? 为啥是质数平方. 因为按照题目要求, x的所有正因数除了自己叫真因数, 恰好有俩的时候这个数就是特殊数字了.
  5. 那为什么是质数不是合数? 因为只有质数的平方的因数才是 1 和 这个质数. 比如 例子里的4 是特殊数字. 可以写成2^2. 那么2 只有 1和2两个因子. 对 4 来说. 除了自己之外, 也就只有1 和 2 了.
  6. 那我们很容易验证, 第二个例子的6 . 因为一眼不是质数平方. 我们计算因子, 就是 1 2 3 了.
  7. 下一个验证一下 9 . 是不是只有 1 和 3?
  8. 思路出现. 开始撸代码. 详见代码块
  9. 为什么做了个开方? 因为要计算区间内的个数, 只需要对两侧数字开平方. 左边 向上取整, 右边向下取整即可获得一个平方区间. 我们很容易就可以在这个区间内找出所有质数...return 齐活.

进阶版思路
埃式筛??? 每天一个没见过的新玩意儿... 反正人家就是快...是埃氏筛和二分查找???哎...这是本渣仰望的高度啊