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

时间:2011-02-12 23:11:34

标签: java math primes


我好像有一个心理障碍,并且无法解决以下问题。基本上,我想找到给定数字中的所有可能的正方形,即N = S * S * A,其中给定数量的N,S * S是正方形,A是其他数字。我需要找到所有可能的组合。
到目前为止,我已经将素数序列中的数字N分解,并构建了一个Map,其中键是序列中唯一的素数,值是该素数的出现次数。
例如,对于某些数字,可能存在这样的序列:
2 2 2 3 3 5 5 5 5 7 7 7 7 7,
因此,方块应为4,9,25,49,36,100,196,225,441,1225。对于这样的顺序,我将有以下地图:
2 3
3 2
5 4
7 5
接下来,我将奇数值减一:
2 2
3 2
5 4
7 4
主要问题是如何从此地图中获取上面写的正方形。我的想法是运行2个循环(不知道效率如何):

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

很明显如何将地图上的所有键对相乘,但我无法想出考虑多重性的条件。
非常感谢你提前! 附:没有嵌套循环有什么好办法吗?

3 个答案:

答案 0 :(得分:3)

我不认为嵌套循环可以帮助你;你正在进入递归领域。 : - )

你问的问题基本归结为此。您有一个数字列表,以及这些数字的频率。您想要提供所有独特的方法,您可以在其中选择每个数字的一​​些副本。例如,给定

2 2
3 4
5 2

你想要

  

2 0 3 0 5 0

     

2 0 3 0 5 2

     

2 0 3 2 5 0

     

2 0 3 2 5 2

     

2 0 3 4 5 0

     

2 0 3 4 5 2

     

2 2 3 0 5 0

     

2 2 3 0 5 2

     

2 2 3 2 5 0

     

2 2 3 2 5 2

     

2 2 3 4 5 0

     

2 2 3 4 5 2

如果我们只是写指数,那么我们有

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

所以问题是如何才能产生这个。幸运的是,有一个非常漂亮的递归公式来生成这些数字。它就是这样的。我们想要编写一个函数AllSquares,它接收一对素数及其多重性的列表,然后返回所有可能的产品,这些产品可以从那些完美正方形的素数形成。我们会以归纳的方式做到这一点。

作为我们的基本情况,如果您向AllSquares提供空列表,那么只有一个方形产品,即1,空列表元素的空产品。

对于归纳步​​骤,假设我们有一个非空列表,其第一个元素是(素数,多重性),其余元素是“休息”。假设我们递归计算通过在列表的其余元素上调用AllSquares形成的列表“组合”。然后对于i = 0,2,4,...,多重性,如果你采用列表中的元素并将它们乘以基数 i ,你将得到一个新的完美正方形列表。如果你取得所有这些值的并集,你最终会得到所有可以从数字中形成的完美正方形。关于这个很酷的部分是,即使多重性是奇数,这也有效,因为你只会考虑指数。

这是一些实现此算法的简单Java代码。它根本没有效率,但它得到了重点:

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

希望这有帮助!

答案 1 :(得分:1)

我解决这个问题的方法是组合问题。

  1. 分解和计算素因子。

  2. 建立一个列表,如果某个因素在原始数字中显示2N2N + 1次,则该因子在此列表中显示为N次。因此,对于2 2 2 2 2 3 3 5的素数因子,列表将为2 2 3

  3. 构建上一个列表的所有组合的列表;例如{2} {2} {3} {2 2} {2 3} {2 3} {2 2 3}

  4. 乘以每组中的因子;例如{2 2 3 4 6 6 12}

  5. 删除重复项以获取S值列表;例如{2 3 4 6 12}

  6. 现在翻译成Java。

    (构建所有组合的列表可以迭代地或递归地完成......或者通过踢和使用第三方库来完成。此外,您可以在步骤3中消除重复;即构建 唯一组合。)

答案 2 :(得分:1)

N = S * S * A计算S的除数并将它们平方。

因此,根据你的地图,你可以将每个指数减半,这样就可以得到S的因子分解。

然后像往常一样计算与所有指数组合相对应的数字以得到除数。

这是我的功能:

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基本上是从元素到非负整数的映射。