【问题标题】:How to find all squares in the number (Java)?如何找到数字中的所有正方形(Java)?
【发布时间】:2011-02-12 23:11:33
【问题描述】:


我似乎有精神障碍,无法解决以下问题。基本上,我想在给定数字中找到所有可能的正方形,即 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()) {
    }
}

很明显,如何将映射中的所有键对相乘,但我无法提出必须强加的条件来考虑多重性。
非常感谢您!
附:有没有没有嵌套循环的好办法?

【问题讨论】:

    标签: java math primes


    【解决方案1】:

    我认为嵌套循环在这里不会对您有所帮助;您正在进入递归领域。 :-)

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

    2 2
    3 4
    5 2
    

    你会想要的

    20 30 50

    20 30 52

    20 32 50

    20 32 52

    20 34 50

    20 34 52

    22 30 50

    22 30 52

    22 32 50

    22 32 52

    22 34 50

    22 34 52

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

    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,即空列表元素的空积。

    对于归纳步​​骤,假设我们有一个非空列表,其第一个元素是 (prime, multiplicity),其余元素是“rest”。假设我们递归地计算通过在列表的其余元素上调用AllSquares 形成的列表“组合”。那么对于 i = 0, 2, 4, ..., 多重性,如果您将列表中的元素乘以 basei,您将得到一个新的完美正方形列表.如果你将所有这些值结合起来,你最终会得到所有可以从数字中形成的完美正方形。很酷的一点是,即使重数是奇数,它也能工作,因为您只考虑偶数指数。

    这里有一些实现该算法的简单 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;
    }
    

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

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

      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}

      现在翻译成Java。

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-05
          • 1970-01-01
          • 2011-11-19
          相关资源
          最近更新 更多