【问题标题】:How to optimize an algorithm with multiple while loops?如何优化具有多个while循环的算法?
【发布时间】:2022-01-06 17:33:44
【问题描述】:

我正在尝试解决 leetcode.com Ugly Number II 上的问题。

问题:丑数是一个正整数,其质因数限制为 2、3 和 5。

给定一个整数n,返回第n个丑数。

示例:

输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是前10个丑数的序列。

这是我的解决方案

class Solution {
    public int nthUglyNumber(int n) {
      int outputNumber = 6;
            int temp = 1;

            if(n<7){return n;}
            int i = 7;
                     while (i !=(n+1)) {
                     outputNumber = outputNumber + 1;
                     temp = outputNumber;

                     while(temp%5==0){temp=temp/5;}
                     while(temp%2==0){temp=temp/2;}

                      while(temp%3==0){temp=temp/3;}



                      if(temp==1) {
                          i=i+1;
                      }
                    }
            return outputNumber;
    }
}

这适用于小数字,但是当输入是大数字时,我有 Time Limit Exceeded 问题是如何优化这段代码?

谢谢!

【问题讨论】:

  • edit发帖并正确格式化代码。
  • 除法(和模)运算是最慢的基本数学运算,比加法要长 40-80 倍。所以你可以尝试通过乘法或加法来“构造”那些丑陋的数字。或者,作为像您这样的更直接的方法:将您已经处理的所有数字保存在一个数组中,并在您的 while 循环中检查这些数字是否已经被识别。对于大量数据,这种方式可以节省大量时间,但会消耗 RAM。
  • while(temp%5==0){temp=temp/5;}temp/(floor(log5(temp))*5)不一样吗?
  • @user1984 不是。

标签: java algorithm while-loop


【解决方案1】:

提示:您正在寻找 2a×3b×5c 形式的数字对于非负整数 a、b、c。与其寻找丑陋的数字,不如直接生成它们不是更容易吗?

【讨论】:

  • 有没有添加LaTeX的好方法?我是新来的溢出,我知道数学堆栈交换支持 LaTeX。
  • 我认为这里不支持。您可以使用非透明背景的 codecogs,但在这个简单的情况下,我认为最好只使用一点 HTML。我已编辑,但可以随意撤消/重写。
【解决方案2】:

我用了两个技巧让它快了两倍,但还是太慢了。我怀疑 check-all-integers-for-ugliness 方法是没有希望的,你会在 LeetCode 的讨论中找到更快的方法。

class Solution {
    public int nthUglyNumber(int n) {
        for (int i = 1; true; i++)
            if (1418776204833984375L % (i / (i & -i)) == 0)
                if (--n == 0)
                    return i;
    }
}

两招:

  • i &amp; -i 提取最低的 1 位,因此除以它会取出每个因子 2。
  • 1418776204833984375 为 319×513。只有因子 3 和 5 的每个正值 int 都会将其除以,而其他所有正值 int 则不会。

【讨论】:

    【解决方案3】:

    我认为最简单的方法是维护一组我们需要访问的丑陋数字。我们从一个只包含1 的集合开始,然后在每一步中,我们删除最小值,并通过将我们的最小值乘以235 来添加找到的值。由于这些可能是重复的(24 = 8 * 324 = 12 * 2),但我们只希望它们一个,我们的集合应该是一个 Set。

    我的 Java 太生疏了,但这里有一个 JavaScript 实现,您可以将其用作伪代码:

    const ugly = (count) => {
      const upcoming = new Set ([1])
      const found = []
      while (found .length < count) {
        const next = Math .min (...upcoming .values ())
        found .push (next)
        upcoming .delete (next)
        upcoming .add (2 * next) 
        upcoming .add (3 * next) 
        upcoming .add (5 * next)
      }
      return found
    }
    
    const uglies = ugly (1690) // This was the upper bound specified in the problem
    
    const nthUglyNumber = (n) =>  uglies [n - 1]
    
    console .log (nthUglyNumber (10))
    console .log (nthUglyNumber (1690))

    ugly 找到第一个 count 丑数,将它们作为数组返回。在内部,它保留了两个集合。 upcoming 是我们知道我们最终会达到的丑陋数字。 found 是我们实际达到的数字数组,总是取 upcoming 值中的最小值。当我们选择下一个时,我们将其从upcoming 中删除并添加到upcoming2-、3- 和5-multiples。

    这可以修改为我们唯一的功能。但是最好为我们的最高值调用一次,并将结果数组存储为uglies。那么nthUglyNumber 是一个简单的函数,可以提取正确索引处的值。

    【讨论】:

      猜你喜欢
      • 2013-03-08
      • 2020-08-13
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      • 2016-03-18
      • 2023-03-18
      相关资源
      最近更新 更多