我有一个获取数组数组并检测是否有子数组出现多次的方法,而不论其顺序如何:
def has_similar_content?(array)
array.each.with_index do |prop1, index1|
array.each.with_index do |prop2, index2|
next if index1 == index2
return true if prop1.sort == prop2.sort
end
end
false
end
> has_similar_content?([%w[white xl], %w[red xl]])
=> false
> has_similar_content?([%w[blue xl], %w[xl blue cotton]])
=> false
> has_similar_content?([%w[blue xl], %w[xl blue]])
=> true
> has_similar_content?([%w[xl green], %w[red xl], %w[green xl]])
=> true
我的问题是此方法的运行时,它具有二次复杂度,并且需要其他类型的数组来检测元素是否相同。
有没有更有效的方法?
答案 0 :(得分:2)
我认为这个问题就是我对此问题的评论中所述的。
代码
def disregarding_order_any_dups?(arr)
arr.map do |a|
a.each_with_object(Hash.new(0)) do |k,h|
h[k] += 1
end
end.uniq.size < arr.size
end
示例
disregarding_order_any_dups? [%w[white xl], %w[red xl]]
#=> false
disregarding_order_any_dups? [%w[blue xl],
%w[xl blue cotton]]
#=> false
disregarding_order_any_dups? [%w[blue xl], %w[xl blue]]
#=> true
disregarding_order_any_dups? [%w[xl green], %w[red xl],
%w[green xl]]
#=> true
disregarding_order_any_dups? [[1,2,3,2], [3,1,3,2],
[2,3,1,2]]
#=> true
复杂度
如果n = arr.size
和m = arr.map(&:size).max
,则计算复杂度为O(n*m
)。 map
块中的单个语句可以用a.sort
代替,但这将使计算复杂度提高到O(n*m*log(m)
)。
说明
对于最后一个示例,步骤如下。
arr = [[1,2,3,2], [3,1,3,2], [2,3,1,2]]
b = arr.map do |a|
a.each_with_object(Hash.new(0)) do |k,h|
h[k] += 1
end
end
#=> [{1=>1, 2=>2, 3=>1}, {3=>2, 1=>1, 2=>1},
# {2=>2, 3=>1, 1=>1}]
c = b.uniq
#=> [{1=>1, 2=>2, 3=>1}, {3=>2, 1=>1, 2=>1}]
d = c.size
#=> 2
e = arr.size
#=> 3
d < e
#=> true
表达式
h = Hash.new(0)
创建一个计数哈希。 Ruby将h[k] += 1
扩展到
h[k] = h[k] + 1
哈希实例方法在左侧的:[]=
,在右侧的:[]
。如果h
没有键k
,则右侧的h[k]
被h
的默认值所取代。等于零,结果:
h[k] = 0 + 1
如果h
具有键k
,则右边的h[k]
不会用k
的默认值替换h
的值。请参见Hash::new的版本,该版本的参数等于哈希的默认值。
答案 1 :(得分:1)
这仍然是二次方,但速度更快:
def has_similar_content?(array)
# sort subarray only once. O( n * m * log(m) )
sorted_array= array.map(&:sort)
# if you can change the input array, this prevent object allocation :
# array.map!(&:sort!)
# compare each pair only once O( n * n/2 )
nb_elements= sorted_array.size
0.upto(nb_elements - 1).each do |i|
(i + 1).upto(nb_elements - 1).each do |j|
return true if sorted_array[i] == sorted_array[j]
end
end
return false
end
答案 2 :(得分:1)
这种方式更简单:
array.
group_by(&:sort).
transform_values(&:length).
values.any? { |count| count > 1 }