打印给定数字的所有因素的独特组合

时间:2013-02-27 21:07:32

标签: java algorithm recursion time-complexity factors

打印正整数因子的所有唯一组合的最有效算法是什么。例如,如果给定的数字是24,那么输出应该是

24*1
12*2
8*3
6*4
6*2*2
4*3*2
3*2*2*2

这里注意到当打印6 * 4时,不打印4 * 6。所以基本上这是一个在不考虑顺序的情况下获取唯一子集的问题(查看问题的一种方法)。但目标是拥有一个运行速度最快的函数,因此将因子存储在数据结构中以进行进一步操作可能会消耗更多时间。我已经尝试了我的算法并在下面粘贴了我的代码,但它似乎没有给我想要的结果,我在递归调用中犯了一些错误。你能帮我找出一个有效的方法吗?

public static void printfact(int num){
        int temp=0;
        for(int i=num-1;i>=num/2;i--){
            if(num % i == 0){
                temp = num/i;
                System.out.println(temp + " * " + i);
                if(isprime(i)==false){
                    System.out.print(temp + " * ");
                    printfact(i);
                }
            }
        }
}

9 个答案:

答案 0 :(得分:4)

尝试这种递归方法,该方法还需要另外2个输入,即一个字符串,用于在for循环中执行i的当前值以执行后续缩减,还使用temp int来知道何时不打印重复的反转,即8 * 3和3 * 8。

public static void printFactors(int number, String parentFactors, int parentVal) {
    int newVal = parentVal;
    for (int i = number - 1; i >= 2; i--) {

        if (number % i == 0) {
            if (newVal > i) {
                newVal = i;
            }
            if (number / i <= parentVal && i <= parentVal
                    && number / i <= i) {
                System.out.println(parentFactors + i + "*" + number / i);
                newVal = number / i;
            }

            if (i <= parentVal) {
                printFactors(number / i, parentFactors + i + "*", newVal);
            }
        }

    }

}

使用printFactors(12,'',12)来调用此方法 如果你发现这种方法存在缺陷,请告诉我。谢谢!

答案 1 :(得分:2)

1)如果是i < numi > num/2,那么num % i == num - i。 (很容易证明。)因此,for循环将毫无意义地检查大于num/2的所有整数,而if语句只会成功temp == 2一次。我认为这不是你想要的。

2)在你解决这个问题时,递归可能需要产生很多答案。但是你只打印一次temp *。所以输出看起来有点奇怪。

3)isprime是不必要的。 num始终是一个合理的因素,无论它是否为素数,只要您遵循以下几点。

4)最后,您需要弄清楚如何避免多次打印出相同的分解。简单的解决方案是仅生成因子单调不增加的因子分解(如在您的示例中)。为了做到这一点,递归需要产生具有一些最大因子的因子分解(这将是先前发现的因子。)因此递归函数应该具有(至少)两个参数:因子数和最大允许因子​​。 (您还需要处理我在第4点中提到的问题。)

以下Python代码确实(我相信)解决了这个问题,但它仍然会做一些不必要的分歧。与python样式的偏差,它打印每个分解而不是作为生成器,因为这将更容易转换为Java。

# Uses the last value in accum as the maximum factor; a cleaner solution
# would have been to pass max_factor as an argument.
def factors(number, accum=[]):
  if number == 1:
    print '*'.join(map(str, accum))
  else:
    if accum:
      max_factor = min(accum[-1], number)
    else:
      max_factor = number
    for trial_factor in range(max_factor, 1, -1):
      remnant = number / trial_factor
      if remnant * trial_factor == number:
        factors(remnant, accum + [trial_factor,])

可以优化for语句。例如,计算remnant后,您知道下一个remnant必须至少有一个更大,因此当trial_factor较小时,您可以跳过一堆remnant

答案 2 :(得分:2)

此代码查找数字的所有因子,对它们进行排序(本地和全局):

public class PrimeFactors {

   final SortedSet< List< Integer >> _solutions = new TreeSet<>(
      new Comparator<List<Integer>>(){
         @Override
         public int compare( List<Integer> left, List<Integer> right ) {
            int count = Math.min( left.size(), right.size());
            for( int i = 0; i < count; ++i ) {
               if( left.get(i) < right.get(i)) {
                  return -1;
               }
               if( left.get(i) > right.get(i)) {
                  return +1;
               }
             }
            return left.size() - right.size();
         }});

   public SortedSet< List< Integer >> getPrimes( int num ) {
      _solutions.clear();
      getPrimes( num, new LinkedList< Integer >());
      return _solutions;
   }

   private void getPrimes( int num, List< Integer > solution ) {
      for( int i = num - 1; i > 1; --i ) {
         if(( num % i ) == 0 ) {
            int temp = num / i;
            List< Integer > s = new LinkedList<>();
            s.addAll( solution );
            s.add( temp );
            s.add( i );
            Collections.sort( s );
            if( _solutions.add( s )) { // if not already found
               s = new LinkedList<>();
               s.addAll( solution );
               s.add( temp );
               getPrimes( i, s );
             }
         }
      }
   }
   public static void main( String[] args ) {
      SortedSet< List< Integer >> solutions =
         new PrimeFactors().getPrimes( 24 );
      System.out.println( "Primes of 24 are:" );
      for( List< Integer > l : solutions ) {
         System.out.println( l );
      }
   }
}

输出:

Primes of 24 are:
[2, 2, 2, 3]
[2, 2, 6]
[2, 3, 4]
[2, 12]
[3, 8]
[4, 6]

答案 3 :(得分:2)

我在C / C ++中没有递归或排序或堆栈的解决方案。

#include <vector>
#include <iostream>

// For each n, for each i = n-1 to 2, try prod = prod*i, if prod < N.

int
g(int N, int n, int k)
{
        int i = k;
        int prod = n;
        std::vector<int> myvec;

        myvec.push_back(n);
        while (i > 1) {
                if (prod * i == N) {
                        prod = prod*i;
                        myvec.push_back(i);
                        for (auto it = myvec.begin();
                                it != myvec.end(); it++) {
                                std::cout << *it << ",";
                        }
                        std::cout << std::endl;
                        return i;
                } else if (prod * i < N) {
                        prod = prod*i;
                        myvec.push_back(i);
                } else { i--;}
        }

        return k;
}

void
f(int N)
{
        for (int i = 2; i <= N/2; i++) {
                int x = g(N, i, i-1);
                // Extract all possible factors from this point
                while (x > 0) {
                        x = g(N, i, x-1);
                }
        }
}

int
main()
{
        f(24);

        return 0;
}

输出是这样的:

$ ./a.out
    3,2,2,2,
    4,3,2,
    6,4,
    6,2,2,
    8,3,
    12,2,

答案 4 :(得分:1)

以下是基于@ rici的想法的解决方案。

def factors(number, max_factor=sys.maxint):
    result = []

    factor = min(number / 2, max_factor)
    while factor >= 2:
        if number % factor == 0:
            divisor = number / factor

            if divisor <= factor and divisor <= max_factor:
                result.append([factor, divisor])

            result.extend([factor] + item for item in factors(divisor, factor))

        factor -= 1

    return result

print factors(12) # -> [[6, 2], [4, 3], [3, 2, 2]]
print factors(24) # -> [[12, 2], [8, 3], [6, 4], [6, 2, 2], [4, 3, 2], [3, 2, 2, 2]]
print factors(157) # -> []

答案 5 :(得分:0)

vector<unsigned int> GetAllFactors(unsigned int number)
{
    vector<unsigned int> factors;

    for (int i = 2; i <= number; i++)
    {
        if (number % i == 0)
        {
            factors.push_back(i);
        }
    }

    return factors;
}

void DoCombinationWithRepetitionFactors(vector<unsigned int> allFactors, unsigned currentProduct, unsigned targetProduct, vector<unsigned int> currentFactorSet, unsigned currentFactorIndex)
{
    if (currentProduct == targetProduct)
    {
        for (auto a : currentFactorSet)
        {
            cout << a << " , ";
        }

        cout << endl;

        return;
    }


    for (int i = currentFactorIndex; i < allFactors.size(); i++)
    {
        if (currentProduct * allFactors[i] <= targetProduct)
        {
            currentFactorSet.push_back(allFactors[i]);
            DoCombinationWithRepetitionFactors(allFactors, currentProduct * allFactors[i], targetProduct, currentFactorSet, i);
            currentFactorSet.pop_back();
        }
    }
}

答案 6 :(得分:0)

bool isprime(int n){
for(int i=2; i<=sqrt(n); i++)
    if(n%i==0)
        return false;
return true;
}

void printprime(int n){

int i,j,y=n;

while(y%2==0){
    cout<<"2 * ";
    y/=2;
}

for(i=3; i<=sqrt(y); i+=2){
    while(y%i==0){
        cout<<i<<" * ";
        y/=i;
    }
}

if(y>2)
    cout<<y;
}

void allfacs(int n){

int i;
unordered_set<int> done;

for(i=2; i<sqrt(n); i++){
    if(n%i==0){
        cout<<i<<" * "<<n/i<<endl;

        if(!isprime(i) && done.find(i) == done.end()){
            done.insert(i);
            printprime(i);
            cout<<n/i<<endl;
        }
        if(!isprime(n/i) && done.find(n/i) == done.end()){
            done.insert(n/i);
            cout<<i<< " * ";
            printprime(n/i);
            cout<<endl;
        }
    }
}
}

答案 7 :(得分:0)

我想出了这个,似乎很容易阅读和理解。希望它有所帮助!

def getFactors(num):

    results = []

    if num == 1 or 0:
        return [num]

    for i in range(num/2, 1, -1):

        if (num % i == 0):
            divisor = num / i

            if(divisor <= i):
                results.append([i, divisor])

            innerResults = getFactors(divisor)

            for innerResult in innerResults:
                if innerResult[0] <= i:
                    results.append([i] + innerResult)

    return results

答案 8 :(得分:0)

#include<bits/stdc++.h>
using namespace std;
int n;
// prod = current product of factors in combination vector
// curr = current factor
void fun(int curr, int prod, vector<int> combination )
{
    if(prod==n)
    {
        for(int j=0; j<combination.size(); j++)
        {
            cout<<combination[j]<<" ";
        }
        cout<<endl; 
        return;
    }

    for(int i=curr; i<n; i++)
    {
        if(i*prod>n) break;
        if(n%i==0)
        {
            combination.push_back(i);
            fun(i, i*prod, combination);
            combination.resize(combination.size()-1);
        }
    }
}

int main()
{
    cin>>n;
    vector<int> combination;
    fun(2, 1, combination);
    cout<<1<<" "<<n;
    return 0;
}