原题是:
Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother to make the gray scale of each cell becomes the average gray scale (rounding down) of all the 8 surrounding cells and itself. If a cell has less than 8 surrounding cells, then use as many as you can.
Example 1:
Input:
[[1,1,1],
[1,0,1],
[1,1,1]]
Output:
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]
Explanation:
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
Note:
The value in the given matrix is in the range of [0, 255].
The length and width of the given matrix are in the range of [1, 150].
思路是:
在原矩阵M的四周,补上一圈值为-1的像素。用一个window的9格list去记录值大于等于0的值,并求平均值。放入结果矩阵result中。
代码是:
import math
class Solution:
def imageSmoother(self, M):
"""
:type M: List[List[int]]
:rtype: List[List[int]]
"""
m = len(M)
n = len(M[0])
result = [[0 for x in range(n)] for y in range(m)]
M.append([-1]*n)
M.insert(0,[-1]*n)
for i in M:
i.insert(0,-1)
i.append(-1)
window = []
for x in range(1,m+1):
for y in range(1,n+1):
window.append(M[x-1][y-1])
window.append(M[x-1][y])
window.append(M[x-1][y+1])
window.append(M[x][y-1])
window.append(M[x][y])
window.append(M[x][y+1])
window.append(M[x+1][y-1])
window.append(M[x+1][y])
window.append(M[x+1][y+1])
ans = [item for item in window if item >= 0]
result[x-1][y-1] = math.floor(sum(ans)/len(ans))
window = []
# M.pop(0)
# M.pop(-1)
# for i in M :
# i.pop(0)
# i.pop(-1)
return result
学到的知识
1.
append只会改变原对象的值,不会返回一个list。
如果M = M.append(....),只会报NoneType没有append attribute属性这个错。
所以append不能连续调用,像javascript那样,
a.append(1).append(3)
同样的道理也对insert有效。
2.
如下的代码犯了一个错误,addOn,插入到list头尾后,M的第一个元素,与M的最后一个元素的索引,指向同一个内存地址。所以会发生同时的改变。
3.
关于list的拷贝
Python中列表和数组的赋值,浅拷贝和深拷贝
列表赋值:
a = [1, 2, 3]
b = a
print b
[1, 2, 3]
a[0] = 0
print b
[0, 2, 3]
解释:[1, 2, 3]被视作一个对象,a,b均为这个对象的引用,因此,改变a[0],b也随之改变
如果希望b不改变,可以用到切片
b = a[:]
a[0] = 0
print b
[1, 2, 3]
解释,切片a[:]会产生一个新的对象,占用一块新的内存,b指向这个新的内存区域,因此改变a所指向的对象的值,不会影响b
列表深拷贝和浅拷贝
浅拷贝
import copy
a = [1, 2, 3, [5, 6]]
b = copy.copy(a)
print b
[1, 2, 3, [5, 6]]
a[3].append('c')
print b
[1, 2, 3, [5, 6, 'c']]
深拷贝
a = [1, 2, 3, [5, 6]]
b = copy.deepcopy(a)
a[3].append('c')
print b
[1, 2, 3, [5, 6]]
拷贝即是开辟一块新的内存空间,把被拷贝对象中的值复制过去。而浅拷贝并没有为子对象[5,6]开辟一块新的内存空间,而仅仅是实现对a中[5,6]的引用。所以改变a中[5,6]的值,b中的值也会发生变化。
深拷贝则是为子对象也开辟了一块新空间。所以改变a中[5, 6]的值,并不影响b
数组赋值不能用切片来达到相同的目的
import numpy as np
a = np.array([1, 2 ,3])
b = a[:]
a[0] = 5
print a, b
[5 2 3] [5 2 3]
如上,虽然用切片,但不能达到修改a而不影响b的目的。说明a,b仍然指向同一块内存。
此时,只能用拷贝
b = a.copy()
a[0] = 5
print a, b
[5 2 3] [1 2 3]
此时修改a不会影响到b。其中的原因以后进一步深究。
注意,列表的拷贝是copy.copy(obj)或copy.deepcopy(obj),数组的拷贝是obj.copy()
本题中,二维数组不能使用copy.copy,本来想要result初始化为M的拷贝,但是不指向M的地址。
最后只能采用了代码中的方法,初始化为一个全部是0的二维List.
4.
在第一版的代码中,第一次使用了map,就地改变List中的所有的值。