【问题标题】:Perfect Powers check完美的权力检查
【发布时间】:2012-01-17 19:24:13
【问题描述】:

完美幂是一个数 N,其中 A^B = N (A >= 1 , B >= 2)

这是我的代码。我试图找出在 1 和我选择的上限之间存在多少这些数字。

    static void Main(string[] args)
    {
        int PPwr_Count = 1; //number 1 is included by default.
        int Top_Limit = 1000000; //Can be any number up to 10^9
        for (int Number = 2; Number <= Top_Limit; Number++)
        {
            int myLog = (int)Math.Floor(Math.Log(Number, 2) + 1);
            for (int i = 2; i <= myLog; i++) 
            {
                //As a Math rule I only need to check below Base 2 Log of number
                int x = Convert.ToInt32(Math.Pow(Number, 1.0 / i));
                 if (Number == Math.Pow(x, i))
                 {
                     PPwr_Count++;
                     break;
                 }
                 else continue;
            }
        }
     } 

目前正在运行。可悲的是,经过大约 1,000,000 次检查后,它变得相当缓慢。有什么办法可以提高这个算法的速度?

【问题讨论】:

  • Perfect power of two between two numbers 的可能重复项 --- 请参阅此以获得更好算法的示例。它特定于2,但很容易适应。
  • @Yuck 我不确定如何轻松调整这些解决方案。该问题中的所有解决方案都使用二进制逻辑,它们之所以有效,是因为该问题专门询问了 2 的幂。在答案可能是 3 的幂的情况下,单独的二进制运算将不起作用。
  • 假设 A 和 B 是整数,您可能需要考虑搜索 B 和 A 而不是搜索 N,因为要考虑的数字要少得多。这里棘手的边界情况是具有多个表示的数字(例如 4^2 = 2^4),因此您需要进行一些额外的排除,而不仅仅是检查 A^B
  • 它不仅仅是 2 的幂,它是任何符合 A^B = N (A >= 1 , B >= 2) 的幂

标签: c# algorithm math


【解决方案1】:

Math.Log 很贵,Math.Pow 很贵,双打很贵。你知道什么不贵吗?乘以整数。

一些理论:如果 A^B == n 且 n=2,则最大 A 接近 5*10^4。所以让我们拥有一套完美的权力。当 i*i

static void Main(string[] args)
    {
        int PPwr_Count = 1; //number 1 is included by default.
        int Top_Limit = 1000000000; //Can be any number up to 10^9
        HashSet<int> hs = new HashSet<int>();

        for (int A = 2; A * A <= Top_Limit; ++A)
        {
            if (!hs.Contains(A))
            {
                //We use long because of possible overflow
                long t = A*A;
                while (t <= Top_Limit)
                {
                    hs.Add((int)t);
                    t *= A;
                    PPwr_Count++;
                }
            }
        }
        Console.WriteLine(PPwr_Count);
    }

编辑:在我的笔记本电脑上调试时运行不到半秒。

【讨论】:

  • 我刚试了一下,效果非常好,非常感谢!
【解决方案2】:

Math.Log(Number, 2) + 1 移出 for 循环。

int myLog = (int)Math.Floor(Math.Log(Number, 2) + 1);
for (int i = 2; i <= myLog; i++) 

【讨论】:

  • 好电话,我什至没有注意到。您应该在回答中解释如何在每次迭代中重新计算 Math.Log(Number, 2) + 1
  • 谢谢。刚刚编辑了我的代码。它改善了时间,但仍然很慢。我相信我的实现应该改变。
【解决方案3】:

在 A 和 B 的空间中搜索比在 N 中搜索更容易。从 [2,...,sqrt(N)] 中搜索 A,从 [List of prime numbers] 中搜索 B。

【讨论】:

    【解决方案4】:

    我倾向于使用完全不同的方法。

    首先,创建一个迭代器,枚举所有质数,直到最大大小的平方根。所以 2、3、5、7、11...

    更新:等一下,这不起作用。例如,36 并不是完美的幂。

    让我修改一下。

    创建一个迭代器,枚举从 2 到最大大小的平方根的所有数字。

    接下来,创建一个迭代器,枚举一个特定给定数字的所有完美幂,直到最大大小。即 22, 23, 24, ...

    现在,将两个迭代器与多选查询结合起来,生成:22、23、24, ... 32, 33, 34, ..., 42, 4 3, 44, ...

    从生成的查询中构建一个哈希集,以形成小于最大大小的所有数字的所有完美幂的并集,直到最大大小的平方根。

    生成的散列集的大小就是你寻找的数字。

    【讨论】:

    • 我喜欢你的想法,谢谢。但是我不明白关于“枚举给定数字的所有完美幂直到最大大小的迭代器”的部分。这不是我真正想要做的吗?你介意再解释一下吗?再次感谢。
    • @JeanCarlosSuárezMarranzini:你说得对,不是很清楚。我会澄清的。
    • 你不需要 As 是素数,只要有 Bs 作为素数就足够了(这是我上面描述的解决方案)。
    【解决方案5】:

    另一种选择不是遍历所有数字并检查它们是否是幂,您可以做相反的事情:生成所有完美的幂。

    所以如果从2开始,计算2^12^2等。然后计算3^13^23^3等。您可能还希望将每个结果存储在 HashSet 中,以便消除双精度。最后,计数就像hash.Count一样简单

    我不确定它的性能如何与您的代码叠加(它肯定会降低空间效率),但另一个角度可能会起作用。

    【讨论】:

    • 哈,我们同时有同样的想法。请注意,您要计算 2^2、2^3 等,而不是从 2^1 开始。如果你从第一个幂开始,那么每个数都是完美的幂。
    【解决方案6】:

    我会尝试从另一个方向处理算法..

    从 a = 2 和 b = 2 开始,遍历每个 b 直到 a ^ b > max_limit

    这个方法的诀窍是只测试 a 的素数值

    此方法的诀窍不是测试完美幂的 a 值(例如,不测试 4、8、9 等)

    【讨论】:

    • 我试过了,但有时数字太高而无法控制。也许我应该向前看去解决它。
    猜你喜欢
    • 2015-08-26
    • 2022-08-23
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 2019-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多