因子成对出现,1
和 24
,2
和 12
,3
和 8
,4
和 6
。
你的算法可以改进的地方是迭代到平方根num
而不是一直到num
,然后使用num / i
计算成对的因子。
for (int i = 1; i * i <= num; i++)
- Abhishek Choudharyx
和 num / x
。由于 9 * 9 <= 90,我们取 9 和 90/9 = 10。 - Abhishek Choudhary你应该检查 num 的平方根,因为 sqrt(num) * sqrt(num) = num:
大致如下:
int square_root = (int) sqrt(num) + 1;
for (int i = 1; i < square_root; i++) {
if (num % i == 0&&i*i!=num)
cout << i << num/i << endl;
if (num % i == 0&&i*i==num)
cout << i << '\n';
}
i<square_root
,i*i<num
,因此无需证明 i*i==num
,在 for 循环之后,您应该证明 square_root*square_root==num
。 - Juanito Perez目前科学界尚未找到算法复杂度高效(即多项式时间复杂度)的方法。因此,按照先前建议的迭代到平方根是最好的方法。
主要因为这个原因,当前使用的加密技术很大程度上基于假设计算任何给定整数的质因数分解需要很长时间。
这是我的代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
#define pii pair<int, int>
#define MAX 46656
#define LMT 216
#define LEN 4830
#define RNG 100032
unsigned base[MAX / 64], segment[RNG / 64], primes[LEN];
#define sq(x) ((x)*(x))
#define mset(x,v) memset(x,v,sizeof(x))
#define chkC(x,n) (x[n>>6]&(1<<((n>>1)&31)))
#define setC(x,n) (x[n>>6]|=(1<<((n>>1)&31)))
// http://zobayer.blogspot.com/2009/09/segmented-sieve.html
void sieve()
{
unsigned i, j, k;
for (i = 3; i<LMT; i += 2)
if (!chkC(base, i))
for (j = i*i, k = i << 1; j<MAX; j += k)
setC(base, j);
primes[0] = 2;
for (i = 3, j = 1; i<MAX; i += 2)
if (!chkC(base, i))
primes[j++] = i;
}
//http://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/
vector <pii> factors;
void primeFactors(int num)
{
int expo = 0;
for (int i = 0; primes[i] <= sqrt(num); i++)
{
expo = 0;
int prime = primes[i];
while (num % prime == 0){
expo++;
num = num / prime;
}
if (expo>0)
factors.push_back(make_pair(prime, expo));
}
if ( num >= 2)
factors.push_back(make_pair(num, 1));
}
vector <int> divisors;
void setDivisors(int n, int i) {
int j, x, k;
for (j = i; j<factors.size(); j++) {
x = factors[j].first * n;
for (k = 0; k<factors[j].second; k++) {
divisors.push_back(x);
setDivisors(x, j + 1);
x *= factors[j].first;
}
}
}
int main() {
sieve();
int n, x, i;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
primeFactors(x);
setDivisors(1, 0);
divisors.push_back(1);
sort(divisors.begin(), divisors.end());
cout << divisors.size() << "\n";
for (int j = 0; j < divisors.size(); j++) {
cout << divisors[j] << " ";
}
cout << "\n";
divisors.clear();
factors.clear();
}
}
第一部分sieve()用于查找质数并将它们放入primes[]数组。请点击链接了解有关该代码(位筛法)的更多信息。
第二部分primeFactors(x)接受一个整数(x)作为输入,并找出其质因数及其对应的指数,并将它们放入vector factors[]中。例如,primeFactors(12)将以以下方式填充factors[]:
factors[0].first=2, factors[0].second=2
factors[1].first=3, factors[1].second=1
如 12 = 2^2 * 3^1
第三部分的setDivisors()函数,利用向量factors[]计算x的所有因子并将它们放入向量divisors[]中,通过递归调用自身实现。
它可以计算任何能放在int中的数字的因子,而且速度相当快。
存在许多很好的解决方案可以找到不太大的数的所有质因子。但我只想指出,一旦你拥有了它们,就不需要进行任何计算即可获得所有的因子。
如果 N = p_1^{a}*p_{2}^{b}*p_{3}^{c}.....
那么因子数量显然为 (a+1)(b+1)(c+1)....
,因为每个因子可以出现零次到a次。
例如,12 = 2^2*3^1
,因此它有3*2=6
个因子。1,2,3,4,6,12
======
我最初认为您只想知道不同因子的数量。但是相同的逻辑也适用。您只需迭代与可能的指数组合相对应的数字集即可。
所以在上面的例子中:
00
01
10
11
20
21
给你 6
个因素。
如果你想打印出所有的因数并按照顺序排列
int i;
for(i=1;i*i<n;i++){ /*print all the divisors from 1(inclusive) to
if(n%i==0){ √n (exclusive) */
cout<<i<<" ";
}
}
for( ;i>=1;i--){ /*print all the divisors from √n(inclusive) to
if(n%i==0){ n (inclusive)*/
cout<<(n/i)<<" ";
}
}
for(int j=1;j*j<=n;j++){
if(n%j==0){
cout<<j<<" ";
if(j!=(n/j))
cout<<(n/j)<<" ";
}
}
两种方法的复杂度均为O(√n)
1:2:2:3:6
。 - Lancepublic static int countAllFactors(int num)
{
TreeSet<Integer> tree_set = new TreeSet<Integer>();
for (int i = 1; i * i <= num; i+=1)
{
if (num % i == 0)
{
tree_set.add(i);
tree_set.add(num / i);
}
}
System.out.print(tree_set);
return tree_set.size();
}
for (int i = 1; i < N; i++) {
for (int j = i; j < N; j += i) {
ans[j].push_back(i);
}
}
Java 8 递归(在 HackerRank 上有效)。此方法包括将因子相加并作为整数返回的选项。
static class Calculator implements AdvancedArithmetic {
public int divisorSum(int n) {
if (n == 1)
return 1;
Set<Integer> set = new HashSet<>();
return divisorSum( n, set, 1);
}
private int divisorSum(int n, Set<Integer> sum, int start){
if ( start > n/2 )
return 0;
if (n%start == 0)
sum.add(start);
start++;
divisorSum(n, sum, start);
int total = 0;
for(int number: sum)
total+=number;
return total +n;
}
}
for( int i = 1; i * i <= num; i++ )
{
/* upto sqrt is because every divisor after sqrt
is also found when the number is divided by i.
EXAMPLE like if number is 90 when it is divided by 5
then you can also see that 90/5 = 18
where 18 also divides the number.
But when number is a perfect square
then num / i == i therefore only i is the factor
*/