前言
最近机试没少吃不会质因数分解的亏,用传统的求得因子个数只能过一点点…(ex, 20%)
质因数分解后,可以将因子问题转化为 集合的组合问题,因此会很快,目测是 l o g n log n logn (n是该整数的值)。
传统解法
假设输入整数的数值是n, 那么时间复杂度就是 n \sqrt{n} n, 显然数字很大时不能接受…
// 朴素方法 sqrt(n)
int calFactorNUmSimple(int num) {unordered_map<int, int> umap;umap[1] = 1;umap[num] = 1;for (int i = 2; i * i <= num; i++) {if (num % i == 0) {umap[i] = 1;umap[num / i] = 1;}}cout << "(simple)factor num: " << umap.size() << endl;// for (auto it: umap)// cout << it.first << " ";// cout << endl;return umap.size();
}
多嘴一句,如果不想输出因子是啥,也不用开一个map, 直接用一个变量存一下个数就行。
int calFactorNUmSimpleJustForNum(int num) {int res = 2;for (int i = 2; i * i <= num; i++) {if (num % i == 0) {res++;if (i != num / i)res++;}}cout << "(simple)factor num: " << res << endl;return res;
}
质因数分解算法
没有仔细求证,目测 O ( l o g n ) O(log n) O(logn) 的时间复杂度。
该算法核心是 将一个数分成一个个质因数集合
,每个值为 i 集合可以选出来 0到 umap[i] 个元素
因此构成的因子种类或者说个数就是 每个集合的个数 + 1
后 再相乘了
比如 108 = 2 2 ∗ 3 3 108 = 2^2 * 3 ^3 108=22∗33, 这个例子中 我们把 108 分成 两个质因数 2 和 3 的集合,他们分别有2个元素和3个元素,
那么总的因子种类就是 我们可以在 2 的集合中取 0 个(0个就是2的0次方就是1)或 1个,2个;
同理,从3的质因数集合中可以取 0个,1个, 2个,3个; 那么最终因数种类就是 ( 2 + 1 ) ( 3 + 1 ) = 12 (2+1) (3+1) = 12 (2+1)(3+1)=12个
具体地,我们从 2的质因数集合中取 1个,从3的质因数集合中取2个,那么当前的因子就是 2 1 × 3 2 = 18 2^1 \times 3^2 = 18 21×32=18。
int calFactorNum(int num) {unordered_map<int, int> umap; int x = num;for (int i = 2; i * i <= x; i++) {while (x % i == 0) {x /= i;umap[i]++;}}if (x > 1) // 没除完,那么 x 本身也是一个质数umap[x]++;// 一个数分成一个个质因数集合,每个值为 i 集合可以选出来 0到umap[i]个元素// 因此构成的因子种类/个数就是 每个集合的个数 + 1 后 再相乘了int res = 1;for (auto it: umap) {// cout << "val: " << it.first << ", exp: " << it.second << endl;res *= (it.second + 1);}cout << "factor num:" << res << endl;return res;
}
lc 2521
2521. 数组乘积中的不同质因数数目
可以练练手
class Solution {
public:int distinctPrimeFactors(vector<int>& nums) {unordered_map<int, int> umap;for(auto x: nums) {// 每个数都来一次质因数分解for (int i = 2; i * i <= x; i++) {while(x % i == 0) {umap[i]++;x /= i;}}if (x > 1)umap[x]++;}return umap.size();}
};
demo完整代码
本案例完整代码 (C++11以上标准即可运行)
//分解质因子
#include <iostream>
#include <unordered_map>
using namespace std;// 输出一下质因数分解
void tryOutputPrimeFactor(int num) {cout << num << "=";int x = num;for (int i = 2; i <= x; i++) { //循环查找判断质因数while (x % i == 0) { //若i为num的质因数,则输出icout << i;x /= i; //对num除以i后的数求取质因数if (x != 1)//判断num是否除尽 cout << "*";}}cout << endl;
}// 朴素方法 sqrt(n)
int calFactorNUmSimple(int num) {unordered_map<int, int> umap;umap[1] = 1;umap[num] = 1;for (int i = 2; i * i <= num; i++) {if (num % i == 0) {umap[i] = 1;umap[num / i] = 1;}}cout << "(simple)factor num: " << umap.size() << endl;// for (auto it: umap)// cout << it.first << " ";// cout << endl;return umap.size();
}int calFactorNUmSimpleJustForNum(int num) {int res = 2;for (int i = 2; i * i <= num; i++) {if (num % i == 0) {res++;if (i != num / i)res++;}}cout << "(simple)factor num: " << res << endl;return res;
}int calFactorNum(int num) {unordered_map<int, int> umap; int x = num;for (int i = 2; i * i <= x; i++) {while (x % i == 0) {x /= i;umap[i]++;}}if (x > 1) // 没除完,那么 x 本身也是一个质数umap[x]++;// 一个数分成一个个质因数集合,每个值为 i 集合可以选出来 0到umap[i]个元素// 因此构成的因子种类/个数就是 每个集合的个数 + 1 后 再相乘了int res = 1;for (auto it: umap) {// cout << "val: " << it.first << ", exp: " << it.second << endl;res *= (it.second + 1);}cout << "factor num:" << res << endl;return res;
}int main()
{int num = 108;// calFactorNUmSimple(num);calFactorNUmSimpleJustForNum(num);calFactorNum(num);return 0;
}
output:
(simple)factor num: 12
factor num:12