我一直在编写一个编码挑战只是为了好玩,问题是这样的:
给定一个仅包含数字的矩形矩阵,计算其中不同的2×2方格的数量。
2x2矩阵可能重叠。输入可以是100 x 100矩阵,并且将是矩形但不一定是正方形。我能够使用嵌套循环解决这个问题,问题是它对于大矩阵的输入来说太慢而且它超过了编码挑战的时间限制(4000ms)。这就是我最初解决它的方式。
def differentSquares(matrix)
i = 0
squares = []
while i < matrix.length - 1
j = 0
while j < matrix[i].length - 1
current = [matrix[i][j], matrix[i][j+1], matrix[i+1][j], matrix[i+1][j+1]]
squares << current if !squares.include?(current)
j += 1
end
i += 1
end
squares.length
end
我已经考虑过以某种方式使用哈希,因为迭代比数组要快得多,但我无法弄清楚如何做到这一点。任何人都可以帮我找到比嵌套循环更快的实现吗?
输入和预期输出的示例:
input:
[[2,5,3,4,3,1,3,2],
[4,5,4,1,2,4,1,3],
[1,1,2,1,4,1,1,5],
[1,3,4,2,3,4,2,4],
[1,5,5,2,1,3,1,1],
[1,2,3,3,5,1,2,4],
[3,1,4,4,4,1,5,5],
[5,1,3,3,1,5,3,5],
[5,4,4,3,5,4,4,4]]
expected output: 54
another input:
[[1,2,1],
[2,2,2],
[2,2,2],
[1,2,3],
[2,2,1]]
expected output: 6
答案 0 :(得分:2)
以下是建议解决方案的集合,包括基准:
require 'benchmark/ips'
require 'set'
require 'matrix'
def generate(x, y, max)
matrix = []
x.times do
row = []
y.times do
row << rand(max)
end
matrix << row
end
matrix
end
def original(matrix)
i = 0
squares = []
while i < matrix.length - 1
j = 0
while j < matrix[i].length - 1
current = [matrix[i][j], matrix[i][j+1], matrix[i+1][j], matrix[i+1][j+1]]
squares << current if !squares.include?(current)
j += 1
end
i += 1
end
squares.length
end
def with_set(matrix)
i = 0
squares = Set.new
while i < matrix.length - 1
j = 0
while j < matrix[i].length - 1
squares << [matrix[i][j], matrix[i][j+1], matrix[i+1][j], matrix[i+1][j+1]]
j += 1
end
i += 1
end
squares.length
end
def with_set_and_length(matrix)
i = 0
squares = Set.new
a = matrix.length - 1
b = matrix.first.length - 1
while i < a
j = 0
while j < b
squares << [matrix[i][j], matrix[i][j+1], matrix[i+1][j], matrix[i+1][j+1]]
j += 1
end
i += 1
end
squares.length
end
def foo(matrix)
matrix.each_cons(2) do |row|
row.each_cons(2) do |col|
end
end
end
def with_each_cons(m)
m.each_cons(2).flat_map { |a, b| a.each_cons(2).zip(b.each_cons(2)) }.uniq.count
end
def with_each_cons_rearanged(m)
m.map { |a| a.each_cons(2).to_a }.each_cons(2).flat_map { |a, b| a.zip(b) }.uniq.count
end
def with_matrix(m)
(m.row_count-1).times.flat_map do |i|
(m.column_count-1).times.map { |j| m.minor(i,2,j,2) }
end.uniq.size
end
def with_matrix_and_set(m)
set = Set.new
(m.row_count-1).times do |i|
(m.column_count-1).times do |j|
set << m.minor(i, 2, j, 2)
end
end
set.size
end
array_matrix = generate(100, 100, 20)
real_matrix = m = Matrix[*array_matrix]
Benchmark.ips do |x|
x.compare!
x.report('original') do
original(array_matrix)
end
x.report('with_set') do
with_set(array_matrix)
end
x.report('with_set_and_length') do
with_set_and_length(array_matrix)
end
x.report('with_each_cons') do
with_each_cons(array_matrix)
end
x.report('with_each_cons_rearanged') do
with_each_cons_rearanged(array_matrix)
end
x.report('with_matrix') do
with_matrix(real_matrix)
end
x.report('with_matrix_and_set') do
with_matrix_and_set(real_matrix)
end
end
结果:
Comparison:
with_set_and_length: 52.7 i/s
with_set: 52.0 i/s - 1.01x slower
with_each_cons_rearanged: 31.4 i/s - 1.68x slower
with_matrix_and_set: 21.0 i/s - 2.52x slower
with_each_cons: 18.7 i/s - 2.82x slower
with_matrix: 17.5 i/s - 3.01x slower
original: 0.1 i/s - 605.89x slower
答案 1 :(得分:1)
这既短又快:
def different_squares(m)
m.each_cons(2).flat_map { |a, b| a.each_cons(2).zip(b.each_cons(2)) }.uniq.count
end
重新排列方法会加快速度:
def different_squares(m)
m.map { |a| a.each_cons(2).to_a }.each_cons(2).flat_map { |a, b| a.zip(b) }.uniq.count
end
答案 2 :(得分:0)
解决Pascal Betz建议使用Set:
require 'set'
def differentSquares(matrix)
i = 0
squares = Set.new
while i < matrix.length - 1
j = 0
while j < matrix[i].length - 1
current = [matrix[i][j], matrix[i][j+1], matrix[i+1][j], matrix[i+1][j+1]]
squares.add(current)
j += 1
end
i += 1
end
squares.length
end
虽然Pascal提到,算法仍然不是很好,我想要一些更好算法的建议。
答案 3 :(得分:0)
require 'matrix'
def nbr_uniq_2x2_submatrices(arr)
m = Matrix[*arr]
(m.row_count-1).times.flat_map do |i|
(m.column_count-1).times.map { |j| m.minor(i,2,j,2) }
end.uniq.size
end
arr = [[2,5,3,4,3,1,3,2],
[4,5,4,1,2,4,1,3],
[1,1,2,1,4,1,1,5],
[1,3,4,2,3,4,2,4],
[1,5,5,2,1,3,1,1],
[1,2,3,3,5,1,2,4],
[3,1,4,4,4,1,5,5],
[5,1,3,3,1,5,3,5],
[5,4,4,3,5,4,4,4]]
nbr_uniq_2x2_submatrices(arr)
#=> 54
类Matrix
的类和实例方法记录在案here。