给定一个二进制矩阵 A
,我们想先水平翻转图像,然后反转图像并返回结果。
水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 [1, 1, 0]
的结果是 [0, 1, 1]
。
反转图片的意思是图片中的 0
全部被 1
替换, 1
全部被 0
替换。例如,反转 [0, 1, 1]
的结果是 [1, 0, 0]
。
示例 1:
输入: [[1,1,0],[1,0,1],[0,0,0]]
输出: [[1,0,0],[0,1,0],[1,1,1]]
解释: 首先翻转每一行: [[0,1,1],[1,0,1],[0,0,0]];
然后反转图片: [[1,0,0],[0,1,0],[1,1,1]]
示例 2:
输入: [[1,1,0,0],[1,0,0,1],[0,1,1,1],[1,0,1,0]]
输出: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
解释: 首先翻转每一行: [[0,0,1,1],[1,0,0,1],[1,1,1,0],[0,1,0,1]];
然后反转图片: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
说明:
1 <= A.length = A[0].length <= 20
0 <= A[i][j] <= 1
最近已经做了好几道关于数组的题啦,废话少说进入正题。
题意:
- 数组逆序
- 元素值取反
思路1.
-
新建一个大小一样的二维数组,然后对元素复制转移。
-
注意:
- 两层for循环的内循环遍历顺序从列尾向前遍历
- 元素取反:公式(n+1)%2
贴上代码
public int[][] flipAndInvertImage(int[][] A) {
int[][] b = new int[A.length][A[0].length];//新建一个同样大小的数组b
int rowN=A.length;//数组的行数
int colN=A[0].length;//数组的列数
for (int i = 0; i <=A.length-1 ; i++) {
for (int j = A[0].length-1; j >=0;j-- ) {//注意此处列循环的初始条件和判出条件
b[i][colN-1-j] = (A[i][j]+1)%2;//元素值取反复制到新的数组当中
}
}
return b;
}
最终测试运行通过
excuse me?
LeetCode平台提交代码,跑85个用例耗时28ms,战胜20%的其他用户。
时间复杂度:(n^2),效率太低。想想优化方案
思路2.
- 还是需要做两层循环遍历,但是如果是逆序的话我们可以对掉数组头和对应数组尾的元素,这样的话只需要循环遍历整个数组一半的元素
-
注意
- 数组列中间的位置为:列数/2
- 中间位置左边的元素游标为0~(列数/2-1)对应中间位置右边的游标:(列数/2+1) ~(列数-1)
- 当列数为偶数时:需要单独对每一行中间值取反,这是我们可以做一个标记,然后在外层循环遍历时对每一行中间元素单独取反操作。
代码如下
public int[][] flipAndInvertImage(int[][] A) {
int colN=A[0].length;
boolean sign =colN%2==0?false:true;//标记当前列数是否为奇数
for (int i = 0; i <=A.length-1 ; i++) {
for (int j = colN/2-1; j >=0;j-- ) {//注意内循环的条件
A[i][j]=(A[i][j]+1)%2;//中间位置左边的元素取非
int temp=(A[i][colN-1-j]+1)%2;//对应右边的元素取非,存在临时变量中
A[i][colN-1-j]=A[i][j];//对掉元素值
A[i][j]=temp;
}
//在外层循环中
if (sign) A[i][colN/2]=(A[i][colN/2]+1)%2;//如果是奇数列中间值取反
}
return A;
}
最终测试运行通过
LeetCode平台提交代码,跑85个用例耗时6ms,战胜97%的其他用户。
时间复杂度:(n^2)/2,稍微优化了下
如果大家有更好的优化方案,欢迎贴出代码!