题意
原地顺时针翻转一个 n*n 的矩阵
图解
下面例子中用 5*5 矩阵做示例,如下图,我们要把该矩阵顺时针翻转90度,并且不能使用另外的矩阵空间来暂存数据,而是原地改变矩阵中数值。
我的想法是这样的:找出翻转的下标变换规律,找出需要变换的位置,将与该位置有关的四个方法(left, top, right, bottom)一次性交换值。
如下图:
首先我从最外围入手,其实整个外围的变化,可以以第一行的 (0, n-2)坐标的元素为基础开始变化,其他三个方向是跟它有关的需要同时变换的元素;
同理,第二行也找到了需要变换的坐标位置;
至于第三行,由于只有一个元素,不需要变换,当然如果你太闲或者觉得代码要统一,变换也不影响什么。(当 n 为偶数的时候,不存在单个元素)
由于上面的例子具有代表性,我们可以从中提取一些规律:
1. 变换的行坐标,从 0 到 Math.floor(n/2)(如下图 i 所示);
2. 变化的列坐标,从 i 到 n-1-i (如下图 j 所示);
3. 变换的坐标公式为:原本位于 (i, j) 的 元素,会变换到 (j, n-1-i) 位置上去。
这个在坐标变换时需要特别注意,因为我们的出发位置不一定是 (i, j),自己做数学公式代入变换的时候,要区分好不同变量,避免逻辑混乱 -- 我自己就比较容易混淆。此外,变换公式如何得到呢?写个例子,列出一些坐标的变动,再根据数据推测一下,最后把其他位置的坐标变动代入验证一下,就能得到。
JavaScript 代码
主要坐标变换如下:
1 let tmp = matrix[i][j]; 2 matrix[i][j] = matrix[n-1-j][i]; 3 matrix[n-1-j][i] = matrix[n-1-i][n-1-j]; 4 matrix[n-1-i][n-1-j] = matrix[j][n-1-i]; 5 matrix[j][n-1-i] = tmp;
完整代码:
var rotate = function(matrix) { let n = matrix.length; let m = Math.floor(n/2); for(let i=0; i<m; i++){ for(let j=i; j<n-1-i; j++){ [matrix[i][j], matrix[n-1-j][i], matrix[n-1-i][n-1-j], matrix[j][n-1-i]] = [matrix[n-1-j][i], matrix[n-1-i][n-1-j], matrix[j][n-1-i], matrix[i][j]]; } } };
结论
做这类坐标变换的题目,主要是寻找坐标变换规律,搞清每次需要动的是哪些元素,目标明确,变换公式明确,其实就没什么大问题。
以前我做这种题目容易出错,主要是因为我心急,不想画例子来分析来看,坐标变换规律也是半懂不懂就开始写代码,偶尔写出来,都是靠运气~
由此可见,保持平稳心态,找准目标,才是真理。