Ruby NxM矩阵遍历
我正在努力解决以下问题的算法: 给定一个只有两个可能值“X”和“O”的矩形矩阵。 值“X”总是以矩形孤岛的形式出现,这些孤岛 始终由至少一行“O”分隔行和列。 计算给定矩阵中的孤岛数 我已经生成了一个解决方案,但是我的循环并没有贯穿整个矩阵。我尝试在I循环中将j初始化为0,但这会引发错误。我对这个主题还不熟悉,我真的想试着理解为什么我的代码不起作用Ruby NxM矩阵遍历,ruby,matrix,traversal,Ruby,Matrix,Traversal,我正在努力解决以下问题的算法: 给定一个只有两个可能值“X”和“O”的矩形矩阵。 值“X”总是以矩形孤岛的形式出现,这些孤岛 始终由至少一行“O”分隔行和列。 计算给定矩阵中的孤岛数 我已经生成了一个解决方案,但是我的循环并没有贯穿整个矩阵。我尝试在I循环中将j初始化为0,但这会引发错误。我对这个主题还不熟悉,我真的想试着理解为什么我的代码不起作用 def matrix(input) row = input.length col = input[0].length counter = 0 i =
def matrix(input)
row = input.length
col = input[0].length
counter = 0
i = 0
j = 0
while i < row do
while j < col do
if input[i][j] == "X"
if i == 0 || input[i-1][j] == "O" && j = 0 || input[i][j-1] == "O"
counter += 1
end
end
j += 1
end
i += 1
end
p counter
end
matrix(
[
["X", "X", "O", "X"],
["X", "X", "O", "X"],
["O", "O", "X", "O"],
["O", "O", "X", "O"],
["O", "O", "O", "X"],
["O", "O", "O", "X"]
]
)
# expected output is 4
def矩阵(输入)
行=input.length
col=输入[0]。长度
计数器=0
i=0
j=0
当我做的时候
而j
这不是家庭作业。我正在练习数据结构和算法。原始问题可以在算法中找到 我们得到一个称为“行”的大小相等的数组
input
。问题中给出的例子如下
input = [
["X", "X", "O", "X"],
["X", "X", "O", "X"],
["O", "O", "X", "O"],
["O", "O", "X", "O"],
["O", "O", "O", "X"],
["O", "O", "O", "X"]
]
为了方便起见,我将元素input[3][2]#=>“X”
称为行3
和列2
中的元素(尽管Ruby没有二维数组或具有行和列的数组的概念)
第一步是构造一个数组groups
,每个元素(一个“组”)由一个元素组成,其中一行的索引为“X”:
groups
#=> [[[0, 0]], [[0, 1]], [[0, 3]], [[1, 0]], [[1, 1]], [[1, 3]],
# [[2, 2]], [[3, 2]], [[4, 3]], [[5, 3]]]
我们现在考虑<代码>组的<元素/代码>的最后一个元素(<代码> [5, 3 ] ] /代码>,并询问它的任何元素(只有一个,<代码>(5, 3)< /代码>)与任何其他组中的元素在同一个岛上。我们发现它与组
[[4,3]]
中的[4,3]
位于同一个岛上(因为元素位于同一列,相隔一行)。因此,我们删除最后一个组,并将其所有元素(此处仅为一个)添加到组[[4,3]]
。我们现在有:
groups
#=> [[[0, 0]], [[0, 1]], [[0, 3]], [[1, 0]], [[1, 1]], [[1, 3]],
# [[2, 2]], [[3, 2]], [[4, 3], [5, 3]]]
我们现在用现在的最后一组重复这个过程,[[4,3],[5,3]]
。我们必须确定该组中的任何一个元素是否与其他组中的任何元素位于同一个岛上。他们不是1。因此,我们确定了第一个岛屿,由位置[4,3]
和[5,3]
组成
初始化孤岛=[]
后,我们执行以下操作:
islands << groups.pop
我们继续这样做,直到组
为空,此时孤岛
的每个元素都是一个孤岛
代码
def find_islands(input)
groups = input.each_with_index.with_object([]) { |(row,i),groups|
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' } }
islands = []
while groups.any?
last_group = groups.pop
idx = groups.each_index.find { |idx| same_island?(groups[idx], last_group) }
if idx.nil?
islands << last_group
else
groups[idx] += last_group
end
end
islands.map(&:sort)
end
def same_island?(group1, group2)
group1.product(group2).any? { |(i1,j1),(i2,j2)|
((i1==i2) && (j1-j2).abs == 1) || ((j1==j2) && (i1-i2).abs == 1) }
end
解释
不可否认,对于一个没有经验的rubest来说,要了解我所介绍的两种方法的工作原理有很多。需要熟悉以下方法:
- 在模块中:
,每个带有索引的单元
,任何?
,查找
,地图
产品
- 类中:
,每个索引
,带对象
下一个
- 课堂上:
,pop
sort
- 课堂上:
abs
- 在模块中:
(记录在)2中nil?
组的初始计算
如果这是一个单独的方法(不是一个坏主意),我们将编写以下内容
def construct_initial_groups(input)
input.each_with_index.with_object([]) { |(row,i),groups|
row.each_with_index { |c,`j| groups << [[i,j]] if c == 'X' } }
end
接下来,我们使用带有_object的方法枚举器#来获得上面的构造_初始_组
的第一种形式
编写块变量(|(行,i),组|
)可能仍然令人困惑。你会知道的
enum = input.each_with_index.with_object([])
#=> #<Enumerator: #<Enumerator: [["X", "X", "O", "X"], ["X", "X", "O", "X"],
# ["O", "O", "X", "O"], ["O", "O", "X", "O"], ["O", "O", "O", "X"],
# ["O", "O", "O", "X"]]:each_with_index>:with_object([])>
Ruby使用消歧或分解为三个块变量中的每一个赋值:
row
#=> ["X", "X", "O", "X"]
i #=> 0
groups
#=> []
然后执行块计算
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' }
#=> ["X", "X", "O", "X"].each_with_index { |c,j| groups << [[i,j]] if c == 'X' }
#=> ["X", "X", "O", "X"]
现在生成enum
的第二个元素,并将其传递给块,然后执行块计算
(row,i), groups = enum.next
#=> [[["O", "O", "X", "O"], 2], [[[1, 0]], [[1, 1]], [[1, 3]]]]
row
#=> ["O", "O", "X", "O"]
i #=> 2
groups
#=> [[[1, 0]], [[1, 1]], [[1, 3]]]
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' }
#=> ["O", "O", "X", "O"]
其余的计算是类似的
同一个岛?方法
假设
group1 #=> [[0, 0], [1, 0]]
group2 #=> [[0, 1], [1, 1]]
这告诉我们,[0,0]
,[1,0]
在同一个岛上,[0,1]
和[1,1]
在同一个岛上,但我们还不知道这四个坐标是否都在同一个岛上。为了确定是否是这种情况,我们将查看所有坐标对,其中一个来自group1
,另一个来自group2
。如果我们将[0,0]
和[1,1]
进行比较,我们不能断定它们位于同一个岛(或不同的岛)上。但是,当我们比较[0,0]
和[0,1]
时,我们看到它们位于同一个岛上(因为它们位于相邻列中的同一行),因此我们推断这两个组的所有元素都位于同一个岛上。例如,我们可以将坐标从group2
移动到group1
,并将group2
从进一步考虑中删除
现在考虑这两个组的方法<代码> SAMEL岛> <代码>所执行的步骤。< /P>
group1 = [[0, 0], [1, 0]]
group2 = [[0, 1], [1, 1]]
a = group1.product(group2)
#=> [[[0, 0], [0, 1]], [[0, 0], [1, 1]], [[1, 0], [0, 1]],
# [[1, 0], [1, 1]]]
(i1,j1),(i2,j2) = a.first
#=> [[0, 0], [0, 1]]
i1 #=> 0
j1 #=> 0
i2 #=> 0
j2 #=> 1
b = i1==i2 && (j1-j2).abs == 1
#=> true
c = j1==j2 && (i1-i2).abs == 1
#=> false
b || c
#=> true
已发现所考虑的第一对坐标位于同一个岛上。(事实上,c
的计算不会执行,因为b
被发现为true
)
find_岛
评论
为了说明所有内容是如何组合在一起的,我将在方法find_islands
中添加注释
def find_islands(input)
groups = input.each_with_index.with_object([]) { |(row,i),groups|
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' } }
islands = []
# the following is the same as: until groups.empty?
while groups.any?
# pop removes and returns last element of `groups`. `groups` is modified
last_group = groups.pop
# iterate over indices of `groups` looking for one whose members
# are on the same island as last_group
idx = groups.each_index.find { |idx| same_island?(groups[idx], last_group) }
if idx.nil?
# last_group is an island, so append it to islands
islands << last_group
else
# groups[idx] members are found to be on the same island as last_group,
# so add last_group to group groups[idx]
groups[idx] += last_group
end
end
# sort coordinates in each island, to improve presentation
islands.map(&:sort)
end
def find_岛(输入)
groups=输入。每个_带有_索引。带有_对象([]){|(行,i),组|
row.each_与_索引{c,j |组算法
我们得到了一个称为“行”的大小相等的数组输入
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' }
#=> ["X", "X", "O", "X"].each_with_index { |c,j| groups << [[i,j]] if c == 'X' }
#=> ["X", "X", "O", "X"]
groups
#=> [[[1, 0]], [[1, 1]], [[1, 3]]]
(row,i), groups = enum.next
#=> [[["O", "O", "X", "O"], 2], [[[1, 0]], [[1, 1]], [[1, 3]]]]
row
#=> ["O", "O", "X", "O"]
i #=> 2
groups
#=> [[[1, 0]], [[1, 1]], [[1, 3]]]
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' }
#=> ["O", "O", "X", "O"]
groups
#=> [[[1, 0]], [[1, 1]],
# [[1, 3]], [[2, 2]]]
group1 #=> [[0, 0], [1, 0]]
group2 #=> [[0, 1], [1, 1]]
group1 = [[0, 0], [1, 0]]
group2 = [[0, 1], [1, 1]]
a = group1.product(group2)
#=> [[[0, 0], [0, 1]], [[0, 0], [1, 1]], [[1, 0], [0, 1]],
# [[1, 0], [1, 1]]]
(i1,j1),(i2,j2) = a.first
#=> [[0, 0], [0, 1]]
i1 #=> 0
j1 #=> 0
i2 #=> 0
j2 #=> 1
b = i1==i2 && (j1-j2).abs == 1
#=> true
c = j1==j2 && (i1-i2).abs == 1
#=> false
b || c
#=> true
def find_islands(input)
groups = input.each_with_index.with_object([]) { |(row,i),groups|
row.each_with_index { |c,j| groups << [[i,j]] if c == 'X' } }
islands = []
# the following is the same as: until groups.empty?
while groups.any?
# pop removes and returns last element of `groups`. `groups` is modified
last_group = groups.pop
# iterate over indices of `groups` looking for one whose members
# are on the same island as last_group
idx = groups.each_index.find { |idx| same_island?(groups[idx], last_group) }
if idx.nil?
# last_group is an island, so append it to islands
islands << last_group
else
# groups[idx] members are found to be on the same island as last_group,
# so add last_group to group groups[idx]
groups[idx] += last_group
end
end
# sort coordinates in each island, to improve presentation
islands.map(&:sort)
end