比嵌套循环更快的算法?

时间:2012-04-15 03:38:43

标签: algorithm loops big-o

对于google codeJam资格赛来说,其中一个问题是找到了多少'回收对'有两个给定的整数。

这是我的解决方案,但它对于大数据输入集来说还不够快。鉴于@a = 10,@ b = 200000,它开始变慢。

我认为我的解决方案是O(2 ^ n)(我还没有掌握大O分析)这太可怕了。我想知道是否有一种标准方法可以通过更快的算法迭代这样的两个循环?

def getPairs
    (@a..@b).each do |n|
      (n..@b).each do |m|
        if (containsSame(n,m)) && (isMatch(@a, n, m, @b))
          @recycledPairs += 1
        end
      end
    end
  end

编辑: 来自Google CodeJam site

  

如果你可以通过从n的后面移动一些数字到前面而不改变它们的顺序来获得m,那么让我们说一对不同的正整数(n,m)被回收。例如,(12345,34512)是一个再生对,因为您可以通过将345从12345的末尾移动到前面来获得34512。请注意,n和m必须具有相同的位数才能成为回收对。 n和m都不能有前导零。

3 个答案:

答案 0 :(得分:3)

您可以阅读the official analysis of this problem以获取正确的解决方案。

基本上,解决方案是为每个n计算大于B但不大于n的所有不同旋转。

答案 1 :(得分:1)

说明中指出“请注意,n和m必须具有相同的位数才能成为回收对。”

你的内循环没有考虑到这一点。如果@a = 2且@b = 20,000,那么你可以删除内部循环的整个块。如果n是两位数,那么您只需要测试m的两位数值。仔细查看内循环的上限。

答案 2 :(得分:1)

声明:max b最多为2 * 10 ^ 6。与所有codejam问题一样,你有多重问题。

第1步:Precalc。对于每个数字n = [1..maxb],保存所有循环的数字严格小于它(每个不超过7),例如

10 - 1
321 - 132, 213

第2步:进行每项测试。遍历从A到B的每个数字,并计算A和B之间的“循环”数。

时间复杂度:步骤1对于每个数字(数字)起作用,即O(ln n)。你必须做b次。总而言之O(b * ln b)。第2步也是如此。对于大型测试用例,这种工作不到一秒钟。