我好像有一个心理障碍,并且无法解决以下问题。基本上,我想找到给定数字中的所有可能的正方形,即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()) {
}
}
很明显如何将地图上的所有键对相乘,但我无法想出考虑多重性的条件。
非常感谢你提前!
附:没有嵌套循环有什么好办法吗?
答案 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)
我解决这个问题的方法是组合问题。
分解和计算素因子。
建立一个列表,如果某个因素在原始数字中显示2N
或2N + 1
次,则该因子在此列表中显示为N
次。因此,对于2 2 2 2 2 3 3 5
的素数因子,列表将为2 2 3
构建上一个列表的所有组合的列表;例如{2} {2} {3} {2 2} {2 3} {2 3} {2 2 3}
。
乘以每组中的因子;例如{2 2 3 4 6 6 12}
。
删除重复项以获取S
值列表;例如{2 3 4 6 12}
。
现在翻译成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
基本上是从元素到非负整数的映射。