提示: 给定一个表示图像灰度的2D整数矩阵M,您需要设计一个更平滑的图像,以使每个单元的灰度变为周围所有8个单元及其自身的平均灰度(向下舍入)。如果一个单元格周围的单元格少于8个,则请尽量使用。
示例:
输入:
[[1,1,1]
[1,0,1]
[1,1,1]]
输出:
[[0,0,0],
[0,0,0],
[0,0,0]]
说明:
For the point (0,0), (0,2), (2,0), (2,2) -> floor(3/4) = floor(0.75) = 0
For the point (0,1), (1,0), (1,2), (2,1) -> floor(5/6) = floor(0.83333333) = 0
For the point (1,1): floor(8/9) = floor(0.88888889) = 0
解决方案:
class Solution:
def imageSmoother(self, grid):
"""
:type M: List[List[int]]
:rtype: List[List[int]]
"""
rows, cols = len(grid), len(grid[0])
#Go through each cell
for r in range(rows):
for c in range(cols):
#Metrics for calculating average, starting inputs are zero since the loop includes the current cell, grid[r][c]
total = 0
n = 0
#Checking the neighbors
for ri in [-1,0,1]:
for ci in [-1,0,1]:
if (r + ri >= 0 and r + ri <= rows-1 and c + ci >=0 and c + ci <= cols-1):
total += grid[r+ri][c+ci]
n += 1
#Now we convert the cell value to the average
grid[r][c] = int(total/n)
return grid
我的解决方案不正确。它通过了一些测试用例,但为此我失败了。
输入: [[2,3,4],[5,6,7],[8,9,10],[11,12,13],[14 ,15,16]]
输出: [[4,4,5],[6,6,6],[8,9,9],[11,11,12],[12 ,12,12]]
预期: [[4,4,5],[5,6,6],[8,9,9],[11,12,12],[13 ,13,14]]
如您所见,我的解决方案非常接近。我不确定自己在哪里搞砸,因为当我更改参数时,我开始在其他基本测试用例中失败。我在网上看到的解决方案使用了其他一些我不想使用的软件包,因为我想更直观地解决这个问题。
您如何检查2D阵列问题出了哪些问题?谢谢!
密码解决方案:
def imageSmoother(self, M):
R,C=len(M),len(M[0])
M2=[[0]*C for i in range(R)]
for i in range(R):
for j in range(C):
temp=[M[i+x][j+y] for x,y in list(itertools.product([-1,0,1],[-1,0,1])) if 0<=i+x<R and 0<=j+y<C ]
M2[i][j]=(sum(temp)//len(temp))
return M2
答案 0 :(得分:2)
您的代码存在问题,因为您正在修改grid
。因此,对于每个单元格,您将使用下/右邻居的输入值,但使用上/左邻居的输出值。
因此,在给定的示例中,当您计算grid[1][0]
的邻居时,您已经替换了grid[0][0]
和grid[0][1]
这两个邻居,因此它们是现在4, 4
,而不是2, 3
。这意味着您正在平均4, 4, 5, 6, 8, 9
而不是2, 3, 5, 6, 8, 9
。因此,您得到的不是6.0而是四舍五入为5。
最简单的解决方法是在进行过程中建立一个新的输出网格,然后将其返回:
rows, cols = len(grid), len(grid[0])
outgrid = []
#Go through each cell
for r in range(rows):
outrow = []
for c in range(cols):
# … same code as before, but instead of the grid[r][c] =
outrow.append(int(total/n))
outgrid.append(outrow)
return outgrid
如果需要在适当的位置修改网格,则可以复制原始网格,然后遍历该副本:
rows, cols = len(grid), len(grid[0])
ingrid = [list(row) for row in grid]
#Go through each cell
for r in range(rows):
for c in range(cols):
# … same code as before, but instead of total += grid[r+ri][c+ci]
total += ingrid[r+ri][c+ci]
如果使用2D NumPy数组而不是列表列表,则可以在更高层次上解决此问题。
NumPy可让您一次添加整个数组,将它们按标量除以此类推,这样您就可以摆脱r
和c
上的那些循环,而只需在整个数组范围内工作即可。但是您仍然必须考虑自己的界限。您不能只添加arr
,arr[:-1]
和arr[1:]
,依此类推,您需要将它们填充到相同的大小。而且,如果只填充0,则最终将平均0, 4, 4, 0, 5, 6, 0, 8, 9
,这是不好的。但是,如果您用NaN
值填充它们,因此要对NaN, 4, 4, NaN, 5, 6, NaN, 8, 9
求平均值,则可以使用nanmean
函数,该函数将忽略那些NaN
值并平均6个实数值。
因此,这仍然是几行代码,可以在9个方向上进行迭代,填充9个数组并nanmean
结果。 (或者您也可以使用product
将其塞入一个巨大的表达式中,例如leetcode答案,但这并没有更容易理解或理解。)
但是,如果您可以拖曳SciPy
(几乎所有您想在NumPy之上构建的所有算法的集合),它的ndimage
库中就有一个名为{{3 }}可以做所有可能的变体,例如“聚集N个邻居,像X那样填充,并在结果数组上运行函数Y”。
在我们的例子中,我们想要收集每轴3个邻居,使用常数NaN填充,并运行nanmean
函数,所以generic_filter
:
scipy.ndimage.generic_filter(grid, function=np.nanmean, size=3, mode='constant', cval=np.NaN)