简体   繁体   English

如何找到数字中的所有平方(Java)?

[英]How to find all squares in the number (Java)?


I seem to have a mental block, and cannot progress with the following problem. 我似乎有精神障碍,无法解决以下问题。 Basically, I want to find all possible squares in a given number, ie N = S*S*A, where N in given number, S*S is a square, and A is some other number. 基本上,我想找到给定数字中的所有可能的平方,即N = S * S * A,其中给定数字中的N,S * S是平方,而A是其他某个数。 And I need to find all possible combinations of that kind. 我需要找到所有可能的组合。
So far I have factorized the number N in a sequence of prime number, and build a Map, where keys are unique prime numbers in the sequence, and values are number of occurrences of this prime number. 到目前为止,我已经将质数序列中的数字N分解,并构建了一个Map,其中键是序列中唯一的质数,而值是该质数的出现次数。
For example, for some number there might be such sequence: 例如,对于某些数字,可能会有这样的顺序:
2 2 2 3 3 5 5 5 5 7 7 7 7 7, 2 2 2 3 3 5 5 5 5 7 7 7 7 7
thus, the squares should be 4, 9, 25, 49, 36, 100, 196, 225, 441, 1225. For such sequence, I will have the following map: 因此,正方形应为4、9、25、49、36、100、196、225、441、1225。对于这样的序列,我将具有以下映射:
2 3 2 3
3 2 3 2
5 4 5 4
7 5 7 5
Next, I decrease odd values by one: 接下来,我将奇数值减1:
2 2 2 2
3 2 3 2
5 4 5 4
7 4 7 4
The main question is how to get squares written above from this map. 主要问题是如何从这张地图上获得上面写的正方形。 My idea was to run 2 loops (no idea how efficient that is): 我的想法是运行2个循环(不知道效率如何):

for(Map.Entry<BigInteger, Integer> entry : frequency.entrySet()) {
    for(Map.Entry<BigInteger, Integer> ientry : frequency.entrySet()) {
    }
}

It is obvious how to multiply all pairs of keys from the map, but I cannot come up with conditions I have to impose to take multiplicities into account. 很明显,如何从映射中乘以所有成对的键,但是我无法提出必须施加的条件来考虑多重性。
Thanks you very much in advance! 提前非常感谢您!
Ps Is there any good way without nested loops? 附言:有没有嵌套循环的好方法吗?

I don't think nested loops are going to help you here; 我认为嵌套循环不会对您有帮助。 you're entering recursion territory. 您正在进入递归区域。 :-) :-)

The problem you're asking essentially boils down to this. 您要问的问题基本上可以归结为这一点。 You have a list of numbers, along with the frequencies of those numbers. 您有一个数字列表,以及这些数字的频率。 You want to come up with all unique ways in which you can choose some number of copies of each number. 您想提出所有可以选择每个号码一定数量副本的独特方法。 For example, given 例如,给定

2 2
3 4
5 2

You'd want 你想要

2 0 3 0 5 0 2 0 3 0 5 0

2 0 3 0 5 2 2 0 3 0 5 2

2 0 3 2 5 0 2 0 3 2 5 0

2 0 3 2 5 2 2 0 3 2 5 2

2 0 3 4 5 0 2 0 3 4 5 0

2 0 3 4 5 2 2 0 3 4 5 2

2 2 3 0 5 0 2 2 3 0 5 0

2 2 3 0 5 2 2 2 3 0 5 2

2 2 3 2 5 0 2 2 3 2 5 0

2 2 3 2 5 2 2 2 3 2 5 2

2 2 3 4 5 0 2 2 3 4 5 0

2 2 3 4 5 2 2 2 3 4 5 2

If we just write the exponents, then we have 如果我们只写指数,那么我们有

0 0 0
0 0 2
0 2 0
0 2 2
0 4 0
0 4 2
2 0 0
2 0 2
2 2 0
2 2 2
2 4 0
2 4 2

So the question is how you can go about generating this. 所以问题是如何去生成它。 Fortunately, there's a really beautiful recursive formulation for generating these numbers. 幸运的是,有一个非常漂亮的递归公式可以生成这些数字。 It goes something like this. 它像这样。 We want to write a function AllSquares that takes in a list of pairs of primes and their multiplicities, then returns all possible products that can be formed from those primes that are perfect squares. 我们要编写一个函数AllSquares ,该函数接受一对素数对及其多重性的列表,然后返回可以由完美平方的素数形成的所有可能乘积。 We'll do this inductively. 我们将归纳地进行此操作。

As our base case, if you provide the empty list to AllSquares , then there is exactly one square product, which is 1, the empty product of the elements of the empty list. 作为我们的基本案例,如果您向AllSquares提供空列表,则正好有一个平方乘积,即1,即空列表元素的空积。

For the inductive step, suppose that we have a nonempty list whose first element is (prime, multiplicity) and whose remaining elements are "rest." 对于归纳步​​骤,假设我们有一个非空列表,其第一个元素为(素数,多重性),其余元素为“其余”。 Suppose that we recursively compute the list "combinations" formed by calling AllSquares on the rest of the elements of the list. 假设我们递归地计算通过在列表的其余元素上调用AllSquares形成的列表“组合”。 Then for i = 0, 2, 4, ..., multiplicity, if you take the elements in the list and multiply them by base i , you'll end up with a new list of perfect squares. 然后对于i = 0、2、4,...,多重性,如果将列表中的元素乘以基数i ,则将得到一个新的理想平方列表。 If you take the union of all of these values, you'll end up with all the possible perfect squares you can form from the numbers. 如果对所有这些值求和,将最终得到可以由数字形成的所有可能的理想平方。 The cool part about this is that this works even if the multiplicities are odd, since you'll only be considering even exponents. 最酷的一点是,即使多重性是奇数,这也可以工作,因为您只需要考虑偶数指数即可。

Here's some simple Java code that implements this algorithm. 这是一些实现此算法的简单Java代码。 It's not at all efficient, but it gets the point across: 它根本不是高效的,但是它可以指出要点:

private static List<Integer> allSquares(List<BaseMultiplicity> elems) {
    /* Base case: If the list is empty, there's only one square. */
    if (elems.isEmpty()) {
        return Collections.singletonList(1);
    }

    /* Recursive case: Compute the answer for the rest of the list. */
    List<BaseMultiplicity> rest = new LinkedList<BaseMultiplicity>(elems);
    rest.remove(0);
    List<Integer> recResult = allSquares(rest);

    /* Now, for each even power of this number, add appropriately-scaled
     * copies of the recursive solution to the result.
     */
    List<Integer> result = new ArrayList<Integer>();
    for (int i = 0, base = 1; i < elems.get(0).multiplicity; 
         i += 2, base *= elems.get(0).prime)
        for (Integer elem: recResult)
            result.add(elem * base * base);

    return result;
}

Hope this helps! 希望这可以帮助!

The way that I'd solve this is as a combinatorial problem. 我要解决的方法是一个组合问题。

  1. factorize and count the prime factors. 分解并计算主要因素。

  2. build a list such that if a factor appears 2N or 2N + 1 times in the original number, the factor appears N times in this list. 建立一个列表,这样如果一个因子在原始数字中出现2N2N + 1次,则该因子在此列表中出现N次。 Thus, for prime factors of 2 2 2 2 2 3 3 5 the list would be 2 2 3 因此,对于2 2 2 2 2 3 3 5的素数,列表将是2 2 3

  3. the build a list of all combinations of the previous list; 构建先前列表的所有组合的列表; eg {2} {2} {3} {2 2} {2 3} {2 3} {2 2 3} . 例如{2} {2} {3} {2 2} {2 3} {2 3} {2 2 3}

  4. multiply the factors in each set; 将每组中的因子相乘; eg {2 2 3 4 6 6 12} . 例如{2 2 3 4 6 6 12}

  5. eliminate duplicates to get the list of S values; 消除重复项以获取S值列表; eg {2 3 4 6 12} . 例如{2 3 4 6 12}

Now translate into Java. 现在翻译成Java。

(Building the list of all combinations can be done iteratively or recursively ... or by punting and using a third party library. Also, you could eliminate the duplicates in step 3; ie build a set of unique combinations.) (构建所有组合的列表可以以迭代或递归的方式进行...或通过插入和使用第三方库来完成。此外,您可以在步骤3中消除重复项;即构建一 唯一的组合。)

For N = S * S * A compute the divisors of S and square them. 对于N = S * S * A计算S的除数并将它们平方。

So given your map you can halve each exponent, this gives you the factorization of S . 因此,根据您的映射,您可以将每个指数减半,这可以使S分解。

Then compute the numbers corresponding to all combinations of exponents to get the divisors, as usual. 然后像往常一样计算与所有指数组合相对应的数字以得到除数。

Here is my function for that: 这是我的功能:

public static NavigableSet<Long> divisors(long n)
{
    NavigableSet<Long> divisors = new TreeSet<Long>();
    divisors.add(1L);
    final Multiset<Long> factorization = primeFactorization(n);
    for (final long primeFactor : factorization.elementSet())
    {
        final int exponent = factorization.getMultiplicity(primeFactor);

        final NavigableSet<Long> newDivisors = new TreeSet<Long>(divisors);
        for (final long d : divisors)
        {
            for (int i = 0; i <= exponent; i++)
            {
                newDivisors.add(d * pow(primeFactor, i));
            }
        }
        divisors = newDivisors;
    }
    return divisors;
}

Multiset is basically a map from elements to non-negative integers. 基本上,多Multiset是从元素到非负整数的映射。

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

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