1、这次记录下循环打印数组,一个多维数组,如下图:

牛客网的修炼之路5-LMLPHP

可以通过下面方式打印:结果为 1,4,4,2,11,1,7,7,7,5,6,9

牛客网的修炼之路5-LMLPHP

打印的时候,不要想着如果通过变换下标来做,而是通过分部分来遍历,我们可以先找出左上角的点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度。如下数组:

牛客网的修炼之路5-LMLPHP

顺时针选择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

如下图:

牛客网的修炼之路5-LMLPHP

因为行列都排好序,所以要利用这个特点,可以从右上角或者左下角进行排序。

比如找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、之字形打印矩阵。如下图打印的结果为:

牛客网的修炼之路5-LMLPHP

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--]);
            	}
            }
	}

}

上述的问题都非常相似,都是有两个独立的坐标来处理。遇到这种矩阵问题时,建议使用这种方式来处理。

10-04 14:50