要求:必须就地完成。
例如:
给定矩阵
1, 2, 3
4, 5, 6
7, 8, 9
应该用3 * 3个相邻单元的总和及其自身的平均值来代替:
(1+2+4+5)/4, (2+1+3+4+5+6)/6 , (3+2+6+5)/4
(1+2+5+4+7+8)/6, (1+2+3+4+5+6+7+8+9)/9, (2+3+5+6+8+9)/6
(4+5+7+8)/4, (4+5+6+7+8+9)/6, (5+6+8+9)/4
是:
All floating number convert to int
3, 3.5(3), 4 3, 3, 4
4.5(4), 5, 5.5(5) => 4, 5, 5
6, 6.5(6), 7 6, 6, 7
我试图迭代矩阵并更新每个单元格,但我发现这会影响未来的计算:
说我更新了原来的1到3,但是当我尝试更新原版2时,原版1现在变为3。
复制原始矩阵以计算平均值是一种解决方法,但这是一个坏主意,我们可以在不使用那么多空间的情况下实现这一目标吗?
答案 0 :(得分:2)
在大多数情况下,您应该只创建原始矩阵的副本,并使用它来计算平均值。除非创建矩阵的副本将使用比可用内存更多的内存,否则开销应该可以忽略不计。
如果你有一个真正的大矩阵,你可以使用“滚动”备份(缺少一个更好的术语)。假设您逐行更新单元格,并且您当前在行 n 中。您不需要备份行 n-2 ,因为这些单元格不再相关,并且行 n + 1 都没有,因为它们仍然是原始的值。所以你可以保留前一行和当前行的备份。每当您前进到下一行时,丢弃上一行的备份,将当前行的备份移动到上一行,并创建新当前行的备份。
一些伪代码(不考虑任何边缘情况):
previous = [] # or whatever works for the first row
for i in len(matrix):
current = copy(matrix[i])
for k in len(matrix[i]):
matrix[i][k] = previous[k-1] + ... + current[k] + ... matrix[i+1][k+1] / 9
previous = current
(您也可以保留 next 行的备份,这样您就可以只使用所有值的备份行,而不必进行区分。)
答案 1 :(得分:0)
您必须为结果数据提供某种缓存,以便您可以继续引用原始数据。我认为没有办法绕过它。
如果数据集很大,您可以通过使用较小的数据缓冲区(如查看锁孔)进行优化,并在更新时“滚动”输入矩阵。在您的情况下,您可以使用小至3x3的缓冲区。 这是速度和空间之间的妥协。缓冲区越小,性能越差。
要显示问题,请从数据集的左上角(0,0)开始:
(为简单起见,结果值向下舍入)
第一步:更新前4个单元格(填充缓冲区)
// Data Set // Data Viewport // Result Set
01,02,03,04,05 01,02,03 04,04,??
06,07,08,09,10 06,07,08 06,07,??
11,12,13,14,15 11,12,13 ??,??,??
16,17,18,19,20
21,22,23,24,25
然后每次迭代..
(用[xx]表示的新值)
++从结果集
更新数据集中的第一列// Data Set // Data Viewport // Result Set
[04],02,03,04,05 01,02,03 04,04,??
[06],07,08,09,10 06,07,08 06,07,??
11 ,12,13,14,15 11,12,13 ??,??,??
16 ,17,18,19,20
21 ,22,23,24,25
++ shift数据视口和结果集右1列
// Data Set // Data Viewport // Result Set
[04],02,03,04,05 02,03,04 04,[03],??
[06],07,08,09,10 07,08,09 07,[08],??
11 ,12,13,14,15 12,13,14 ??, ?? ,??
16 ,17,18,19,20
21 ,22,23,24,25
++更新结果集的中间列
// Data Set // Data Viewport // Result Set
[04],02,03,04,05 02,03,04 04,[05],??
[06],07,08,09,10 07,08,09 07,[08],??
11 ,12,13,14,15 12,13,14 ??, ?? ,??
16 ,17,18,19,20
21 ,22,23,24,25
在接下来的迭代中,数据状态为:
// Data Set // Data Viewport // Result Set
04,[04],03,04,05 03,04,05 05,[06],??
06,[07],08,09,10 08,09,10 08,[09],??
11, 12 ,13,14,15 13,14,15 ??, ?? ,??
16, 17 ,18,19,20
21, 22 ,23,24,25
..等等
不要忘记处理其他边缘情况。
* 数据视口表示仅用于可视化。在代码中,实际视口将是结果缓冲区。