如何降低此功能的复杂性?

时间:2015-04-28 10:58:16

标签: ruby algorithm time-complexity

我有这个功能:

def get_sum_slices(a, sum)
  count = 0
  a.length.times do |n|
    a.length.times do |m|
      next if n > m
      count += 1 if a[n..m].inject(:+) == sum
    end
  end
  count
end

将此[-2, 0, 3, 2, -7, 4]数组和2作为和,它将返回2,因为切片的两个总和等于0 - [2][3, 2, -7, 4]。有人知道如何将其提高到O(N * log(N))?

3 个答案:

答案 0 :(得分:4)

我对ruby并不熟悉,但在我看来,你正试图找出总共sum总共有多少个连续的子数组。

你的代码正在蛮力发现所有子阵列 - O(N^2),并将它们相加 - 每个O(N),并检查它是否匹配。
这总计为O(N^3)代码。

可以更有效地完成 1

定义一个新数组sums,如下所示:

sums[i] = arr[0] + arr[1] + ... + arr[i]

O(N)时间内计算上述内容很容易。请注意,假设为非负数 - 此sums数组已排序。

现在,迭代sums数组,并对每个元素sums[i]执行二分搜索,如果有一些索引j使sums[j]-sums[i] == SUM。如果答案是真的,加一个(如果数组可以包含零,则需要更简单的工作,它不会影响复杂性。)

由于搜索是二进制搜索,并且每次迭代都在O(logN)完成,并且您为每个元素执行此操作 - 实际上您拥有O(NlogN)算法。

同样地,但是将sums中的元素添加到哈希集中而不是将它们放在排序数组中,您可以达到O(N)平均大小写性能,因为现在寻找每个元素{{1平均而言。

伪代码:

O(1)

请注意,哈希集变体不需要限制非负数,也可以处理它。

(1)假设你的数组只包含非负数。

答案 1 :(得分:1)

根据amit的算法:

def get_sum_slices3(a, sum)
  s = a.inject([]) { |m, e| m << e + m.last.to_i }
  s.sort!
  s.count { |x| s.bsearch { |y| x - y == sum } }
end

Ruby使用的quicksort在大多数情况下是nlogn

答案 2 :(得分:0)

您应该更好地详述您在此尝试实现的目标。无论如何,计算具有特定总和的子阵列的数量可以这样做:

def get_sum_slices(a, sum) 
  count = 0
  (2..a.length).each do |n|
    a.combination(n).each do |combination|
      if combination.inject(:+) == sum
        count += 1
        puts combination.inspect
      end
    end
  end
  count
end

btw你的例子应该返回6

irb> get_sum_slices [-2, 0, 3, 2, -7, 4], 0
[-2, 2]
[-2, 0, 2]
[3, -7, 4]
[0, 3, -7, 4]
[-2, 3, 2, -7, 4]
[-2, 0, 3, 2, -7, 4]
=> 6