1、这次记录下循环打印数组,一个多维数组,如下图:
可以通过下面方式打印:结果为 1,4,4,2,11,1,7,7,7,5,6,9
打印的时候,不要想着如果通过变换下标来做,而是通过分部分来遍历,我们可以先找出左上角的点leftTop(leftTopRow,leftTopColumn),然后找到右下角的点rightBottom(rightBottomRow,rightBottomColumn),然后开始从leftTopColumn开始遍历就是(0,0),(0,1),(0,2)然后当leftTopColumn < rightBottomColumn 不满足,即3<3,就停止,注意,此时最后一个节是没有遍历到的,再从rightBottomColumn,开始遍历,即(0,3),(1,3)此时leftTopRow < rightBottomRow不满足,即 2<2不满足,所以就停止,然后再到rightBottomColumn开始减少遍历,即是(2,3),(2,2),(2,1)然后同理停止,然后就是(2,0),(1,0),停止。里面的圈就是 leftTop(leftTopRow+1,leftTopColumn+1)和 rightBottom(rightBottomRow-1,rightBottomColumn-1)。此时比较特殊行相等,只要从左往右打印就行了,同样的如果是列相等,则从上到下打印就行了。最后的然后继续左上角的加1和右下角的减一操作,只要行数或者列数超过了,就停止打印。
则打印有三种:一种:行相等,一种:列相等,一种:不相等的情况
package com.lizhi.java8;
public class CirclePrint {
public static void main(String[] args) {
int[][] arrs = { { 1, 4, 4, 2 }, { 5, 6, 9, 11 },{7,7,7,1}};
// 左上角的行
int leftTopRow = 0;
// 左上角的列
int leftTopColumn = 0;
// 右下角的行
int rightBottomRow = arrs.length - 1;
// 右下角的列
int rightBottomColumn = arrs[0].length - 1;
while (leftTopRow <= rightBottomRow && leftTopColumn <= rightBottomColumn) {
cicle(arrs, leftTopRow, leftTopColumn, rightBottomRow, rightBottomColumn);
//下面四行,就是所谓的左上角下移,右上角上移
leftTopRow++;
leftTopColumn++;
rightBottomRow--;
rightBottomColumn--;
}
}
private static void cicle(int[][] arrs, int leftTopRow, int leftTopColumn, int rightBottomRow,
int rightBottomColumn) {
//需要记住一开始左上角的位置,为了从右往左打印
//从下到上打印时,找到边界
int tempLeftTopColumn = leftTopColumn;
int tempLeftTopRow = leftTopRow;
//如果行数相等,则从左往右打印即可
if(leftTopRow == rightBottomRow) {
while(leftTopColumn <= rightBottomColumn) {
System.out.println(arrs[leftTopRow][leftTopColumn++]);
}
//如果列数相等,从上到下打印
}else if(leftTopColumn == rightBottomColumn) {
while(leftTopRow <= rightBottomRow) {
System.out.println(arrs[leftTopRow++][leftTopColumn]);
}
}else {
//都相等,则转圈打印,其实是四个打印
//从左到右打印,行数不变
while(leftTopColumn < rightBottomColumn) {
System.out.println(arrs[leftTopRow][leftTopColumn++]);
}
//从上到下打印,列数不变
while(leftTopRow < rightBottomRow) {
System.out.println(arrs[leftTopRow++][leftTopColumn]);
}
//从右往左打印,行数不变
while(leftTopColumn > tempLeftTopColumn) {
System.out.println(arrs[leftTopRow][leftTopColumn--]);
}
//从下到上打印,列数不变
while(leftTopRow > tempLeftTopRow) {
System.out.println(arrs[leftTopRow--][leftTopColumn]);
}
}
}
}
不过我发现了一个问题,就是可以不考虑行数相等,或者列数相等的情况。
举个例子,如果同一行的话,那么从上到下和从下到上肯定就不打印了,则从左往右打印,会剩最后一个不打印,然后从右往左打印,那么也会打印出这相等行数;同理,列相等也是一样的。代码如下:
package com.lizhi.java8;
public class CirclePrint {
public static void main(String[] args) {
int[][] arrs = { { 1, 4, 4, 2 }, { 5, 6, 9, 11 }};
// 左上角的行
int leftTopRow = 0;
// 左上角的列
int leftTopColumn = 0;
// 右下角的行
int rightBottomRow = arrs.length - 1;
// 右下角的列
int rightBottomColumn = arrs[0].length - 1;
while (leftTopRow <= rightBottomRow && leftTopColumn <= rightBottomColumn) {
cicle(arrs, leftTopRow, leftTopColumn, rightBottomRow, rightBottomColumn);
//下面四行,就是所谓的左上角下移,右上角上移
leftTopRow++;
leftTopColumn++;
rightBottomRow--;
rightBottomColumn--;
}
}
private static void cicle(int[][] arrs, int leftTopRow, int leftTopColumn, int rightBottomRow,
int rightBottomColumn) {
//需要记住一开始左上角的位置,为了从右往左打印
//从下到上打印时,找到边界
int tempLeftTopColumn = leftTopColumn;
int tempLeftTopRow = leftTopRow;
//从左到右打印,行数不变
while(leftTopColumn < rightBottomColumn) {
System.out.println(arrs[leftTopRow][leftTopColumn++]);
}
//从上到下打印,列数不变
while(leftTopRow < rightBottomRow) {
System.out.println(arrs[leftTopRow++][leftTopColumn]);
}
//从右往左打印,行数不变
while(leftTopColumn > tempLeftTopColumn) {
System.out.println(arrs[leftTopRow][leftTopColumn--]);
}
//从下到上打印,列数不变
while(leftTopRow > tempLeftTopRow) {
System.out.println(arrs[leftTopRow--][leftTopColumn]);
}
}
}
2、对正方形的数组,顺时针旋转90度。如下数组:
顺时针选择90度后,即是1到12的位置,4到9的位置,12到11的位置,9到7的位置,11到8的位置,7到5的位置,8到1的位置,
此时最外层就完成了。然后里层,只有一个不用转。注意到这个条件了没,还是跟上面一样,通过转圈的方式,而且只要左上角的行数小于右下角的行数即可,相等时也忽略。代码如下:
package com.lizhi.java8;
public class Rotate {
public static void main(String[] args) {
int[][] arrs = { { 1, 2, 3 ,4}, { 2, 4, 7 ,9}, { 3, 5, 9,10 } ,{ 2, 3, 7,8 } };
// 左上角的行
int leftTopRow = 0;
// 左上角的列
int leftTopColumn = 0;
// 右下角的行
int rightBottomRow = arrs.length - 1;
// 右下角的列
int rightBottomColumn = arrs[0].length - 1;
//不能等于,因为一相等就时重合了,也就是才一个点,就无法转了
while(leftTopRow < rightBottomRow) {
rotate(arrs, leftTopRow, leftTopColumn, rightBottomRow, rightBottomColumn);
//同样的,左上角的点往下,右下角的点往上
leftTopRow++;
leftTopColumn++;
rightBottomRow--;
rightBottomColumn--;
}
//用于测试的数据
for(int i = 0; i< arrs.length;i++) {
for(int j = 0; j < arrs[0].length;j++) {
System.out.print(arrs[i][j]+" ");
}
System.out.println();
}
}
private static void rotate(int[][] arrs, int leftTopRow, int leftTopColumn, int rightBottomRow,
int rightBottomColumn) {
//交换的外层循环的次数,因为是90度,所以第一行的第一个数
//跑到第一行的最后一个数的位置,反正这里是每一个点,就要把
//该点对应要动的所以点调整完。即这里就是四个角的点的调整。
//然后是第二个,一致下去,到移动到最后一个时,就不用调整了。
//也就是第一个的纵坐标不能跟最后的一个数的纵坐标相等,所以index < times
int times = rightBottomRow -leftTopRow;
int index = 0;
int temp = 0;//交换时临时变量
while(index < times) {
//这里慢慢扣吧,有规律的,不太好说
temp = arrs[leftTopRow][leftTopColumn+index];
arrs[leftTopRow][leftTopColumn+index] = arrs[rightBottomRow-index][leftTopColumn];
arrs[rightBottomRow-index][leftTopColumn] = arrs[rightBottomRow][rightBottomColumn-index];
arrs[rightBottomRow][rightBottomColumn-index] = arrs[leftTopRow+index][rightBottomColumn];
arrs[leftTopRow+index][rightBottomColumn] = temp;
index++;
}
}
}
3、在行列都排好顺序的二维数组中找某个数。
当然你可以通过双层循环来处理,不过这样的话,时间复杂度就变成了,n*m
如下图:
因为行列都排好序,所以要利用这个特点,可以从右上角或者左下角进行排序。
比如找8这个数,我这里选择从右上角开始遍历,那么先和7比较,比7大,所以就往下走。然后和9比较,比9小,那么往左边走,和8相等,找到。从这里可以看出,最差的情况是到11这个位置,而此时的时间复杂度尾n+m。
package com.cjh.niukewang;
public class FindNum {
public static void main(String[] args) {
int[][] arrs = {{2,5,7},{6,8,9},{11,14,15}};
System.out.println(isExist(arrs, 2));
}
public static boolean isExist(int[][] arrs,int num) {
int row = 0;
int col = arrs[0].length-1;
while(col >= 0 && row <= arrs.length-1) {
//相等,返回true
if(arrs[row][col] == num) {
return true;
//num比较大,所以要向下移动
}else if(num > arrs[row][col] ){
row++;
//num比较小 ,所以向左移动
}else if(num < arrs[row][col]){
col--;
}
}
return false;
}
}
4、之字形打印矩阵。如下图打印的结果为:
2,5,6,11,8,11,9,14,15,12,17的结果。两个点,A一个向右移动,B一个向下移动,当A到达最右边的时候,就行数加一,列数不变。B到底最下点的时候,行数不变,列数加一,期间有个对角线打印的函数,分别有从上到下打印和从下到上打印。
代码如下:
package com.cjh.niukewang;
public class Zprint {
public static void main(String[] args) {
int[][] arrs = { { 2, 5, 7,11 }, { 6, 8, 9 ,12}, { 11, 14, 15,17 } };
zprint(arrs);
}
private static void zprint(int[][] arrs) {
int aRow = 0;
int aCol = 0;
int bRow = 0;
int bCol = 0;
int endRow = arrs.length - 1;
int endCol = arrs[0].length - 1;
boolean flag = true;// 从下往上打
while (aRow <= endRow) {
printNum(arrs,aRow, aCol, bRow, bCol, flag);
//a的行不变,如果到达到列最后一列,一直加1
aRow = aCol == endCol ? aRow+1 : aRow;
//a的列一直加1,如果到列最后一列,就不变
aCol = aCol == endCol ? aCol : aCol+1;
//b的列一直不变,当b的行到最后一行的时候,开始加1
bCol = bRow == endRow ? bCol+1: bCol;
//b的行一直加1,当b的到达最后一行的时候,不变。
bRow = bRow == endRow ? bRow : bRow+1;
flag = !flag;//从上到下打印
}
}
private static void printNum(int[][] arrs,int aRow, int aCol, int bRow, int bCol, boolean flag) {
if(flag) {
//从下到上打印
while(bCol <= aCol) {
System.out.println(arrs[bRow--][bCol++]);
}
}else {
//从上到下打印
while(aRow <= bRow) {
System.out.println(arrs[aRow++][aCol--]);
}
}
}
}
上述的问题都非常相似,都是有两个独立的坐标来处理。遇到这种矩阵问题时,建议使用这种方式来处理。