简体   繁体   English

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

[英]Print all unique combination of factors of a given number

What is the most efficient algorithm to print all unique combinations of factors of a positive integer. 打印正整数因子的所有唯一组合的最有效算法是什么。 For example if the given number is 24 then the output should be 例如,如果给定的数字是24,那么输出应该是

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

Here notice that when 6*4 gets printed then 4*6 doesn't get printed. 这里注意到当打印6 * 4时,不打印4 * 6。 So basically it's a problem of taking unique subsets without considering the order (one way to look at the problem). 所以基本上这是一个在不考虑顺序的情况下获取唯一子集的问题(查看问题的一种方法)。 But the objective is to have a function that runs the fastest, so storing the factors in a data structure to do further manipulation might consume more time. 但目标是拥有一个运行速度最快的函数,因此将因子存储在数据结构中以进行进一步操作可能会消耗更多时间。 I have tried my algorithm and pasted my code below, but it doesn't seem to give me the desired result, I'm making some mistake in my recursive call. 我已经尝试了我的算法并在下面粘贴了我的代码,但它似乎没有给我想要的结果,我在递归调用中犯了一些错误。 Can you help me figure out an efficient way to do this? 你能帮我找出一个有效的方法吗?

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

Try this recursive approach that also takes in 2 more inputs namely a string to carry over the current value of i in for loop to perform subsequent reduction and also a temp int to know when not to print duplicate reversals ie, 8*3 and 3*8. 尝试这种递归方法,它还需要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);
            }
        }

    }

}

And call this method using printFactors(12,'',12) 并使用printFactors调用此方法(12,'',12)
Let me know if you find flaws in this approach. 如果你发现这种方法存在缺陷,请告诉我。 Thanks! 谢谢!

1) If i < num and i > num/2 , then num % i == num - i . 1)如果i < numi > num/2 ,则num % i == num - i (Easy to prove.) So your for loop will pointlessly check all the integers greater than num/2 and the if statement will only succeed once, with temp == 2 . (很容易证明。)所以你的for循环将毫无意义地检查大于num/2所有整数, if语句只会成功一次, temp == 2 I don't think that's what you wanted. 我不认为这就是你想要的。

2) In you fixed that, the recursion might need to produce a lot of answers. 2)在你修复它时,递归可能需要产生很多答案。 But you only print temp * once. 但是你只打印一次temp * So the output will look a bit wierd. 所以输出看起来有点奇怪。

3) isprime is unnecessary. 3) isprime是不必要的。 num is always a legitimate factor, whether or not it is prime, provided you follow the point below. 如果你遵循以下几点, num始终是一个合理的因素,无论它是否是素数。

4) Finally, you need to figure out how to avoid printing out the same factorization multiple times. 4)最后,您需要弄清楚如何避免多次打印出相同的分解。 The easy solution is to only produce factorizations where the factors are monotonically non-increasing (as in your example). 简单的解决方案是仅生成因子单调不增加的因子分解(如在您的示例中)。 In order to do that, the recursion needs to produce factorizations with some maximum factor (which would be the previously discovered factor.) So the recursive function should have (at least) two arguments: the number to factor and the maximum allowed factor. 为了做到这一点,递归需要产生具有一些最大因子的因子分解(这将是先前发现的因子。)因此递归函数应该具有(至少)两个参数:因子数和最大允许因子​​。 (You also need to deal with the problem I noted as point 4.) (你还需要处理我在第4点注意到的问题。)

The following Python code does (I believe) solve the problem, but it still does quite a few unnecessary divides. 以下Python代码确实(我相信)解决了这个问题,但它仍然会做一些不必要的分歧。 In a deviation from python style, it prints each factorization instead of acting as a generator, because that will be easier to translate into Java. 与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,])

It is possible to optimize the for statement. 可以优化for语句。 For example, once you compute remnant , you know that the next remnant must be at least one greater, so you can skip a bunch of trial_factor values when remnant is small. 例如,一旦你计算了remnant ,你知道下一个remnant必须至少有一个更大,所以当remnant很小时你可以跳过一堆trial_factor值。

This code find all the factors of a number, sort them (locally and globally): 此代码查找数字的所有因子,对它们进行排序(本地和全局):

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

Outputs: 输出:

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

I have a solution without recursion or sorting or stacks in C/C++. 我在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;
}

And output is like this: 输出是这样的:

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

Here is my solution based on @rici's ideas. 这是我基于@ 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) # -> []
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();
        }
    }
}
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;
        }
    }
}
}

I came up with this, seems easy to read and understand. 我想出了这个,似乎很容易阅读和理解。 Hope it helps! 希望能帮助到你!

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
#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM