前言
最近机试没少吃不会质因数分解的亏,用传统的求得因子个数只能过一点点…(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的质因数,则输出i
cout << 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