加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何确定Big O比较Ruby中的两个数组

发布时间:2020-12-17 03:57:11 所属栏目:百科 来源:网络整理
导读:我的算法技巧很黯淡.我创建了一个方法来查看两个数组是否包含相同的元素(重复无关紧要): one = [1,"taco",3,2,:piece,4,5,5]two = [:piece,1,3]def same_elements?(array_one,array_two) return true if ( (array_one - array_two).empty? (array_two - arr
我的算法技巧很黯淡.我创建了一个方法来查看两个数组是否包含相同的元素(重复无关紧要):

one = [1,"taco",3,2,:piece,4,5,5]
two = [:piece,1,3]

def same_elements?(array_one,array_two)
  return true if ( (array_one - array_two).empty? && (array_two - array_one).empty? )
  return false
end

same_elements?(one,two)

这返回true(这是正确的).问题是,我不确定这个算法的效率是多少.我的第一个猜测是O(n ^ 2),因为我们必须同时检查a-b和b-a.我知道O(n ^ 2)非常可怕.有没有更有效的方法来做到这一点?

解决方法

简短的回答

平均为O(n m)

最糟糕的情况是O(nm),但只有在你真的想要实现它时才会发生(参见最后一段).

如果选择array_one大于array_two,则O(m n)只是O(n),因此该算法平均以线性时间运行.

替代

另一种更简短的检查方法是:

one = [1,3]

puts Set[*one] == Set[*two] #=> true
# or
puts one.to_set == two.to_set #=> true

小重构

return true if x
return false

等同于

x

所以你的代码可以写成:

def same_elements?(array_one,array_two)
  (array_one - array_two).empty? && (array_two - array_one).empty?
end

基准

我用1E6元素创建了一个数组,其中一半是0到199999之间的随机数(用于碰撞),另一半是纯Ruby对象.

另一个数组就是第一个,随机洗牌.

N = 1_000_000

one = (1..N).map{rand < 0.5 ? rand(N/5) : Object.new}
two = one.sort_by{rand}

比较集合需要1分钟,而设置比较的fruity报告比OP的方法快20%.

对于较小的整数数组,OP的方法要快一些.

注意:@engineersmnky在评论中提出的代码报告速度与其他方法相似.

时间复杂

当与通常的阵列一起使用时,你的代码肯定不是O(nm).

大概时间是:

1E4> 1s
1E5> 8s
1E6> 160s

看看array.c中的rb_ary_diff,难怪上面描述的所有方法都在同一时间运行:它们的工作方式基本相同.

rb_ary_diff为array_two(在O(m)中)创建一个哈希表,并迭代遍历array_one的每个元素(在O(n)中),查找哈希表中的值(平均为O(1)).整个操作平均为O(n m).

blog post分析了set intersection,它以非常类似的方式实现.

两次这样做不会改变任何东西,因此整体时间复杂度保持为O(n m).

寻找O(mn)

制作此算法O(mn)的一种方法是完全禁用散列方法.除了证明这是一个非常糟糕的主意之外,没有理由这样做.

使用10_000个KeyObjects:

class KeyObject < Object
end

集合比较不到1秒.

使用10_000个KeyObjects:

class KeyObject < Object
  def hash
    1
  end
end

集合比较需要超过14分钟!

2个不同的随机Ruby对象具有相同散列的概率大约是1E-20.严格来说,这个算法的最坏情况是O(mn),但是如果你不去寻找它就永远不会发生.找到与2个元素的碰撞并非易事,找到与1E6元素的碰撞不会偶然发生.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读