簡體   English   中英

有效地獲得給定數字的所有除數

[英]Efficiently getting all divisors of a given number

根據這篇文章,我們可以通過以下代碼獲得一個數字的所有除數。

for (int i = 1; i <= num; ++i){
    if (num % i == 0)
        cout << i << endl;
}

例如,數字24的除數是1 2 3 4 6 8 12 24

搜索了一些相關的帖子,沒有找到好的解決辦法。 有沒有什么有效的方法來實現這一點?

我的解決方案:

  1. 通過此找出給定數的所有質因數。
  2. 獲取這些主要因素的所有可能組合。

然而,它似乎不是一個好方法。

因素是成對的。 1242123846

算法的改進可能是迭代到num平方根而不是一直到num ,然后使用num / i計算配對因子。

你真的應該檢查直到 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';
}

目前在科學上已知的算法復雜度(具有多項式復雜度的算法)意義上沒有有效的方法。 因此,迭代直到已經建議的平方根大部分都盡可能好。

主要是因為這個,目前使用的密碼學的很大一部分是基於這樣的假設,即計算任何給定整數的質因數分解是非常耗時的。

這是我的代碼:

#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) 作為輸入,找出它的素因子和對應的指數,並將它們放入向量 factor[] 中。 例如, primeFactors(12) 將以這種方式填充 factor[]:

factors[0].first=2, factors[0].second=2
factors[1].first=3, factors[1].second=1

因為 12 = 2^2 * 3^1

第三部分 setDivisors() 遞歸調用自身來計算 x 的所有除數,使用向量 factor[] 並將它們放入向量 divisors[] 中。

它可以計算適合 int 的任何數字的除數。 它也非常快。

有很多很好的解決方案可以找到不是太大的數的所有質因數。 我只是想指出,一旦你有了它們,就不需要計算來獲得所有的因素。

如果N = p_1^{a}*p_{2}^{b}*p_{3}^{c}.....

然后的因素的數量顯然是(a+1)(b+1)(c+1)....由於各因素可出現次。

例如12 = 2^2*3^1所以它有3*2 = 6因子。 1,2,3,4,6,12

======

我最初認為您只想要不同因素的數量。 但同樣的邏輯也適用。 您只需遍歷與可能的指數組合相對應的一組數字。

所以在上面的例子中:

00
01
10
11
20
21

給你6因素。

這是這種方法的 Java 實現:

public 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();
}

如果您希望按排序順序打印所有除數

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)

//Try this,it can find divisors of verrrrrrrrrry big numbers (pretty efficiently :-))
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<conio.h>

using namespace std;

vector<double> D;

void divs(double N);
double mod(double &n1, double &n2);
void push(double N);
void show();

int main()
{
    double N; 
    cout << "\n Enter number: "; cin >> N;

    divs(N); // find and push divisors to D

    cout << "\n Divisors of "<<N<<": "; show(); // show contents of D (all divisors of N)

_getch(); // used visual studio, if it isn't supported replace it by "getch();"
return(0);
}

void divs(double N)
{
    for (double i = 1; i <= sqrt(N); ++i)
    {
        if (!mod(N, i)) { push(i); if(i*i!=N) push(N / i); }
    }
}

double mod(double &n1, double &n2)
{
    return(((n1/n2)-floor(n1/n2))*n2);
}

void push(double N)
{
    double s = 1, e = D.size(), m = floor((s + e) / 2);
    while (s <= e)
    {   
        if (N==D[m-1]) { return; }
        else if (N > D[m-1]) { s = m + 1; }
        else { e = m - 1; }
        m = floor((s + e) / 2);
    }
    D.insert(D.begin() + m, N);
}

void show()
{
    for (double i = 0; i < D.size(); ++i) cout << D[i] << " ";
}
int result_num;
bool flag;

cout << "Number          Divisors\n";

for (int number = 1; number <= 35; number++)
{
    flag = false;
    cout << setw(3) << number << setw(14);

    for (int i = 1; i <= number; i++) 
    {
        result_num = number % i;

        if (result_num == 0 && flag == true)
        {
            cout << "," << i;
        }

        if (result_num == 0 && flag == false)
        {
            cout << i;
        }

        flag = true;
    }

    cout << endl;   
}
cout << "Press enter to continue.....";
cin.ignore();
return 0;
}
for (int i = 1; i*i <= num; ++i)
{
    if (num % i == 0)
    cout << i << endl;
    if (num/i!=i)
    cout << num/i << endl;
}
//DIVISORS IN TIME COMPLEXITY sqrt(n)

#include<bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{
    ll int n;
    cin >> n;

    for(ll i = 2;  i <= sqrt(n); i++)
    {
        if (n%i==0)
        {
            if (n/i!=i)
                cout << i << endl << n/i<< endl;
            else
                cout << i << endl;
        }
    }
}
#include<bits/stdc++.h> 
using namespace std;
typedef long long int ll;
#define MOD 1000000007
#define fo(i,k,n) for(int i=k;i<=n;++i)
#define endl '\n'
ll etf[1000001];
ll spf[1000001];
void sieve(){
    ll i,j;
    for(i=0;i<=1000000;i++) {etf[i]=i;spf[i]=i;}
    for(i=2;i<=1000000;i++){
        if(etf[i]==i){
            for(j=i;j<=1000000;j+=i){
                etf[j]/=i;
                etf[j]*=(i-1);
                if(spf[j]==j)spf[j]=i;
            }
        }
    }
}
void primefacto(ll n,vector<pair<ll,ll>>& vec){
    ll lastprime = 1,k=0;
    while(n>1){
        if(lastprime!=spf[n])vec.push_back(make_pair(spf[n],0));
        vec[vec.size()-1].second++;
        lastprime=spf[n];
        n/=spf[n];
    }
}
void divisors(vector<pair<ll,ll>>& vec,ll idx,vector<ll>& divs,ll num){
    if(idx==vec.size()){
        divs.push_back(num);
        return;
    }
    for(ll i=0;i<=vec[idx].second;i++){
        divisors(vec,idx+1,divs,num*pow(vec[idx].first,i));
    }
}
void solve(){
    ll n;
    cin>>n;
    vector<pair<ll,ll>> vec;
    primefacto(n,vec);
    vector<ll> divs;
    divisors(vec,0,divs,1);
    for(auto it=divs.begin();it!=divs.end();it++){
        cout<<*it<<endl;
    }
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    sieve();
    ll t;cin>>t;
    while(t--) solve();
    return 0;
}

我們可以使用修改篩來獲取范圍 [1, N-1] 中所有數字的所有因子。

for (int i = 1; i < N; i++) {
    for (int j = i; j < N; j += i) {
        ans[j].push_back(i);
    }
}

時間復雜度為O(N * log(N)),因為諧波級數1 + 1/2 + 1/3 + ... + 1/N的總和可以近似為log(N)

有關時間復雜度的更多信息: https : //math.stackexchange.com/a/3367064

PS:通常在編程問題中,任務將包括多個查詢,其中每個查詢代表不同的數字,因此一次預先計算范圍內所有數字的除數將是有益的,因為在這種情況下查找需要 O(1) 時間。

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
*/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM