题目:
You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
Follow up:
Could you do this in-place?
链接: http://leetcode.com/problems/rotate-image/
题解:
in-place,按照顺时针移动整个矩阵的1/4,注意边长为奇数时的corner case。 还有方法是对折再变换的。
Time complexity - O(n2), Space Complexity - O(1)
public class Solution { public void rotate(int[][] matrix) { if(matrix == null || matrix.length == 0) return; int n = matrix.length - 1; for(int i = 0; i <= n / 2; i++) { for(int j = 0; j < (n + 1) / 2; j++) { int tmp = matrix[i][j]; matrix[i][j] = matrix[n - j][i]; matrix[n - j][i] = matrix[n - i][n - j]; matrix[n - i][n - j] = matrix[j][n - i]; matrix[j][n - i] = tmp; } } } }
Follow up是对矩阵最外部的元素,每个元素向右移动一个位置。可能药用spiral matrix一类的方法。
再Follow up可以 design一个三消游戏,类似 Candy Crush saga。
二刷:
这里看漏了n x n matrix,其实m = n就可以了。注意遍历的边界条件, i 可以 < n /2, 这样j就必须要 j < (n + 1) / 2来cover中间的奇数元素。还可以想得再透彻一些。还有不少大神有很好的翻转方法,先记录在reference里,留给三刷了。
Java:
Time complexity - O(n2), Space Complexity - O(1)
public class Solution { public void rotate(int[][] matrix) { if (matrix == null || matrix.length == 0) { return; } int m = matrix.length, n = matrix[0].length; for (int i = 0; i < m / 2; i++) { for (int j = 0; j < (n + 1) / 2; j++) { int tmp = matrix[i][j]; matrix[i][j] = matrix[m - 1 - j][i]; matrix[m - 1 - j][i] = matrix[m - 1 - i][n - 1 - j]; matrix[m - 1 - i][n - 1 - j] = matrix[j][n - 1 - i]; matrix[j][n - 1 - i] = tmp; } } } }
同时也做了一下 Rotate Matrix by 1, 发了一篇新文
题外话:
1/27/2016
今天群里讨论interval search tree,很精彩。我打算好好复习一下相关的知识。昨天讨论Google面试题密码箱问题,de brujin, hamiton path和 euler path,还是要好好向dietpepsi大神学习。 要扎实,反应敏捷并且准确,还要能迅速写出代码才能。现在差得还很远。
三刷:
这里的边界条件要注意一下。因为题目给出m = n,所以input是边长都是n的方阵。 我们旋转的方阵分为两种,一种是边长为奇数的,一种是边长为偶数的。
旋转边长为偶数的矩阵时,我们要根据 len / 2 把矩阵分为四个部分,只需要旋转左上部分就行了,比如n = 4,那么我们的条件就是 i < 2和 j < 2。
[1, 2, 3, 4]
[5, 6, 7, 8]
[1, 2, 3, 4]
[5, 6, 7, 8]
另外一种是奇数边长的矩阵,这时候我们旋转的也是左上部分,不过左上部分这时候不是一个方阵,而是一个类似于三角形,或者梯形的区域。比如下图,这里其实我们要旋转的是1和2,或者1和4。假如我们同时旋转1, 2和4, 那么就会出现重复步骤造成结果不正确。
所以这时候我们对边长的界定应该是, i < (len + 1) / 2, 即对row 添加1然后除以2,转换成偶数边长时遍历的情况, 而 j < len / 2, 对j来说不变,还是维持奇数边长时遍历的情况。当然这里我们也可以互换i 和 j。 这样处理就保证了我们在操作的时候没有多余步骤。
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
Java:
public class Solution { public void rotate(int[][] matrix) { if (matrix == null) return; int len = matrix.length; for (int i = 0; i < (len + 1) / 2; i++) { for (int j = 0; j < len / 2; j++) { int tmp = matrix[i][j]; matrix[i][j] = matrix[len - 1 - j][i]; matrix[len - 1 - j][i] = matrix[len - 1 - i][len - 1 - j]; matrix[len - 1 - i][len - 1 - j] = matrix[j][len - 1 - i]; matrix[j][len - 1 - i] = tmp; } } } }
Reference:
https://leetcode.com/discuss/20589/a-common-method-to-rotate-the-image
https://leetcode.com/discuss/38426/seven-short-solutions-1-to-7-lines
https://leetcode.com/discuss/27262/java-in-place-solution-with-explanation-easy-to-understand