【问题标题】:Algorithm for listing all multiples possible by set of numbers than is less than x用小于 x 的一组数列出所有可能的倍数的算法
【发布时间】:2015-11-30 06:33:34
【问题描述】:

我正在尝试解决一个更大的算法的子问题,我真的在努力解决这个问题!

问题

如果我有一个数字数组(比如 A),我如何有效地列出所有可以通过将数字相乘得到的数字(可以根据需要使用多次) 并且小于另一个数字(比如 x)。

例如,假设我有 A = [7, 11, 13] 并且 x 是 1010,答案将是:

 - 7 = 7
 - 11 = 11
 - 13 = 13
 - 7*7 = 49
 - 7*11 = 77
 - 7*13 = 91
 - 11*11 = 121
 - 11*13 = 143
 - 13*13 = 169
 - 7*7*7 = 343
 - 7*7*11 = 539
 - 7*7*13 = 637
 - 7*11*11 = 847
 - 7*11*13 = 1001

我已尽力不遗漏任何内容(但如果有,请随时编辑)!

我可以看出这可能是某种类型的递归,但我真的在这方面苦苦挣扎!

可选

一个天真的解决方案也很好(这就是我正在苦苦挣扎的地方)。

运行时间也是可选的。

更新

A中的所有数都是从eratosthenes筛中得到的所有素数(1、2、3、5除外)。

更新 2

A也已排序

更新 3 A中的所有数字都在限制范围内

更新 4 解决方案不需要递归。那只是我的一个想法。 Java 或伪代码更可取!

【问题讨论】:

  • 是否所有数字都像您的示例中的素数一样,或者是否允许复合?
  • 是的,数字是质数(除了 1、2、3、5)。我使用 eratosthenes 筛来获得所有素数。
  • 您的数组是否包含 ALL 个低于限制的素数(此处限制为 1010)?
  • 是的,低于限制

标签: algorithm recursion primes prime-factoring number-theory


【解决方案1】:

我会使用队列。我想到的算法类似于以下(伪代码):

multiplyUntil(A, X)
{
    queue q = A.toQueue();
    result;

    while(!q.isEmpty())
    {
        element = q.pop();
        result.add(element); // only if the initial elements are guaranteed to be < X otherwise you should add other checks

        for(int i = 0; i < A.length; i++)
        {
            product = element * A[i];

            // A is sorted so if this product is >= X the following will also be >= X
            if(product >= X)
            {
                // get out of the inner cycle
                break;
            }

            q.add(product);
        }
    }

    return result;
}

如果有不清楚的地方请告诉我。

P.S:请记住,结果不能保证是排序的。如果您希望对结果进行排序,您可以使用堆而不是队列,或者在计算结束时对结果进行排序。

【讨论】:

  • 是否有任何性能增强考虑到 A 已排序。谢谢!
  • 我编辑了代码,所以它跳过了肯定是 >= X 的元素。除了这个增强之外,我现在什么都没有想到。如果出现其他问题,我会通知您。
【解决方案2】:

这是关于 Java 和 cmets 的解决方案。将其翻译成其他语言非常简单。

// numbers is original numbers like {7, 11, 13}, not modified
// offset is the offset of the currently processed number (0 = first)
// limit is the maximal allowed product
// current array is the current combination, each element denotes
//   the number of times given number is used. E. g. {1, 2, 0} = 7*11*11
private static void getProducts(int[] numbers, int offset, int limit, int[] current) {
    if(offset == numbers.length) {
        // all numbers proceed: output the current combination
        int product = 1;
        StringBuilder res = new StringBuilder();
        for(int i=0; i<offset; i++) {
            for(int j = 0; j<current[i]; j++) {
                if(res.length() > 0) res.append(" * ");
                res.append(numbers[i]);
                product *= numbers[i];
            }
        }
        // instead of printing you may copy the result to some collection
        if(product != 1)
            System.out.println(" - "+res+" = "+product);
        return;
    }
    int n = numbers[offset];
    int count = 0;
    while(limit >= 1) {
        current[offset] = count;
        getProducts(numbers, offset+1, limit, current);
        count++;
        // here the main trick: we reduce limit for the subsequent recursive calls
        // note that in Java it's integer division
        limit/=n;
    }
}

// Main method to launch    
public static void getProducts(int[] numbers, int limit) {
    getProducts(numbers, 0, limit, new int[numbers.length]);
}

用法:

public static void main(String[] args) {
    getProducts(new int[] {7, 11, 13}, 1010);
}

输出:

 - 13 = 13
 - 13 * 13 = 169
 - 11 = 11
 - 11 * 13 = 143
 - 11 * 11 = 121
 - 7 = 7
 - 7 * 13 = 91
 - 7 * 11 = 77
 - 7 * 11 * 13 = 1001
 - 7 * 11 * 11 = 847
 - 7 * 7 = 49
 - 7 * 7 * 13 = 637
 - 7 * 7 * 11 = 539
 - 7 * 7 * 7 = 343

生成的产品以不同的方式排序,但我想排序不是一个大问题。

【讨论】:

    【解决方案3】:

    这是我在 C++ 中的解决方案。我使用递归函数。原理是:

    • 给递归函数一个limit,一个current,它是一个组合和一系列素数[start, end(
    • 它将输出给定范围内所有素数的幂的组合,乘以current 复合

    在每一步,该函数从范围中获取第一个素数p,并计算其所有幂。然后,只要乘积 cp 低于限制,它就会将 current 乘以 p

    我们使用的事实是,一旦cp 超过限制,数组就会被排序。

    由于我们计算数字的方式,它们不会被排序。但是,一旦您收集了数字,很容易将其添加为最后一步(在这种情况下,您将使用back_inserter 输出迭代器而不是ostream_iterator,并在收集向量上执行sort

    #include <algorithm>
    #include <iostream>
    #include <iterator>
    
    using namespace std;
    
    template <class It, class Out>
    void f(int limit, int current, It start, It end, Out out) {
    
      // terminal condition                                                                                
      if(start == end) {
        if(current != 1)
          *(out++) = current;
        return;
      }
    
      // Output all numbers where current prime is a factor                                                
      // starts at p^0 until p^n where p^n > limit                                                         
      int p = *start;
      for(int cp = current; cp < limit; cp *= p) {
        f(limit, cp, start+1, end, out);
      }
    }
    
    int main(int argc, char* argv[]) {
      int const N = 1010;
      vector<int> primes{7, 11, 13};
    
      f(N, 1, begin(primes), end(primes), ostream_iterator<int>(cout, "\n"));
    }
    

    【讨论】:

    • 注意:答案不需要是递归的!那只是一个建议。如果作为循环更好,请使用循环(无论如何我更喜欢循环)。当然,如果使用递归更有意义,请使用递归
    • 同样高效,递归函数更短。
    猜你喜欢
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多