1、螺旋打印矩阵

以下都要求:额外空间复杂度为O(1),即只用变量,原地打印

先确定左上点和右下点,先打出边框,然后向内调整点的位置,循环打印,如图所示:
算法 (七)矩阵相关:螺旋打印矩阵、旋转正方形矩阵、之字形打印矩阵、在行列都排好序的矩阵中找数
完整代码如下

package cn.nupt;

/**
 * @Description: 顺时针螺旋打印矩阵
 *
 * @author PizAn
 * @date 2019年2月16日 下午10:01:39 
 * 
 */

public class PrintMatrixSpiralOrder {

	public void printMatrixSpiralOrder(int[][] arr) {
		int tR = 0; // 左上角点的行号
		int tC = 0; // 左上角点的列号
		int dR = arr.length - 1; // 右下角点的行号:就是一维数组的数目 - 1
		int dC = arr[0].length - 1; // 右下角点的列号:就是一维数组的长度

		while (tR <= dR && tC <= dC) {
			printLine(arr, tR++, tC++, dR--, dC--); // 打印以这四个点围成的边界,然后缩小圈子

		}

	}

	private void printLine(int[][] arr, int tR, int tC, int dR, int dC) {
		if (tR == dR) { // 行相同,即当还剩一列的时候,从上到下打印这一列(因为是顺时针旋转,必定是一圈打完之后调整四个点的位置)
		
		/*	for (int i = tC; i <= dC; i++) {
				System.out.println(arr[tR][i] + " ");
			}*/
			
			while (tC <= dC) {
				System.out.println(arr[tR][tC++]);
			}

		} else if (tC == dC) {// 列相同,即当还剩一行的时候,从左道由打印这一行(因为是顺时针旋转)
		
		/*	for (int i = tR; i <= dR; i++) {
				System.out.println(arr[i][tC] + " ");

			}*/
			
			while (tR <= dR) {
				System.out.println(arr[tR++][tC]);
				
			}

		}else { //打印边框
			int curC = tC;
			int curR = tR;
			
			while (curC != dC) {
				System.out.println(arr[tR][curC++] + " ");
				
			}
			while (curR != dR) {
				System.out.println(arr[curR++][dC]+ " ");
				
			}
			while (curC != tC) {
				System.out.println(arr[dR][curC--]+ " ");
				
			}
			while (curR != tR) {
				System.out.println(arr[curR--][tC]+ " ");
				
			}
			
		}

	}
}

2、90*旋转正方形矩阵

其实这个思路和上面的一样,从微观来操作,同样是从边框入手,依次交换90*边界上的几个点,然后缩小边界框,如下图所示

算法 (七)矩阵相关:螺旋打印矩阵、旋转正方形矩阵、之字形打印矩阵、在行列都排好序的矩阵中找数

具体代码如下:

package cn.nupt;

/**
 * @Description: 顺时针将矩阵旋转90*
 *
 * @author PizAn
 * @date 2019年2月16日 下午10:02:40
 * 
 */
public class RotateMatrix {

	public void rotateMatrix(int[][] arr) {

		int tR = 0; // 左上角点的行号
		int tC = 0; // 左上角点的列号
		int dR = arr.length - 1; // 右下角点的行号:就是一维数组的数目 - 1
		int dC = arr[0].length - 1; // 右下角点的列号:就是一维数组的长度

		while (tR < dR) {
			rotatePoint(arr, tR++, tC++, dR--, dC--);

		}

	}
	
	//依次交换边界上的几个点
	private void rotatePoint(int[][] arr, int tR, int tC, int dR, int dC) {
		int times = dC - tC;
		int temp = 0;
		for (int i = 0; i < times; i++) {
			temp = arr[tR][tC + i];
			arr[tR][tC + i] = arr[dR - i][tC];
			arr[dR - i][tC] = arr[dR][dC - i];
			arr[dR][dC - i] = arr[tR + i][dC];
			arr[tR + i][dC] = temp;
		}

	}
	---------------------------------------------------
	//打印数组
	public void show(int[][] arr) {
		for (int i = 0; i < arr.length; i++) {
			for (int j = 0; j < arr[0].length; j++) {
				System.out.print(arr[i][j] + "  ");
			}
			System.out.println();
		}
		
	}

}

3、之字形打印矩阵算法 (七)矩阵相关:螺旋打印矩阵、旋转正方形矩阵、之字形打印矩阵、在行列都排好序的矩阵中找数

代码描述如下:

package cn.nupt;

import java.awt.dnd.DnDConstants;

/**
 * @Description: "之"字形打印矩阵
 *
 * @author PizAn
 * @date 2019年2月17日 下午2:23:39
 * 
 */
public class ZigZagPrintMatrix {

	
	public static void printarrZigZag(int[][] arr) {
		// 定义两个点A和B,各自的坐标初始化在左上角,
		int aR = 0;
		int aC = 0;
		int bR = 0;
		int bC = 0;
		// 矩阵右下角的点的坐标
		int enbR = arr.length - 1;
		int enbC = arr[0].length - 1;
		boolean flag = false;
		// 我们开始移动左上角的两个点,这是边界的约束,即还没有到右下角的时候(注,A和B走的总路程是一样的)
		while (aR != enbR + 1) {
			// 打印A和B所在斜线上的点
			printLevel(arr, aR, aC, bR, bC, flag);
			
			// 调整A和B的位置,沿着边框走,遇到边界就拐弯,直到走到最下面的时候
			aR = aC == enbC ? aR + 1 : aR;
			aC = aC == enbC ? aC : aC + 1;
			bC = bR == enbR ? bC + 1 : bC;
			bR = bR == enbR ? bR : bR + 1;
			// 为了能"之"字形打印,这里要将方向转一下,使用flag实现的
			flag = !flag;
		}
		System.out.println();
	}
	
	// 打印A和B所在斜线上的点
	public static void printLevel(int[][] m, int aR, int aC, int bR, int bC,
			boolean f) {
		if (f) {
			while (aR != bR + 1) {
				System.out.print(m[aR++][aC--] + " ");
			}
		} else {
			while (bR != aR - 1) {
				System.out.print(m[bR--][bC++] + " ");
			}
		}
	}
	
	
	
	/*
	另一种写法
	
	public void zigZagPrintMatrix(int[][] arr) {

		int aR = 0; // 定义两个点A和B,各自的坐标初始化在左上角,
		int aC = 0;
		int bR = 0;
		int bC = 0;

		int dR = arr.length - 1; // 矩阵右下角的点的坐标
		int dC = arr[0].length - 1;

		boolean flag = true;

		while (aC != dC + 1) { // 我们开始移动左上角的两个点,这是边界的约束,即还没有到右下角的时候(注,A和B走的总路程是一样的)
			// 打印A和B所在斜线上的点
			printLine(arr, aR, aC, bR, bC, flag);
			// 调整A和B的位置,沿着边框走,遇到边界就拐弯,直到走到最下面的时候
			bR = bC == dC ? bR + 1 : bR;
			bC = bC == dC ? bC : bC + 1;
			aR = aR == dR ? aR : aR + 1;
			aC = aR == dR ? aC + 1 : aC;

			// 为了能"之"字形打印,这里要将方向转一下,使用flag实现的
			flag = !flag;

		}

	}

	// 打印A和B所在斜线上的点
	private void printLine(int[][] arr, int aR, int aC, int bR, int bC, boolean flag) {

		if (flag) {
			while (bR != aR + 1) {
				System.out.println(arr[bR++][bC--]);
			}
		} else {
			while (aR != bR - 1) {
				System.out.println(arr[aR--][aC++]);
			}
		}
	}
	*/



}


4、在行列都排好序的矩阵中找数

时间复杂度为O(N+M),额外空间复杂度为O(1)

因为是行列都排好序的,所以要充分利用这个条件,如下图所示,从右上角的数开始:

  1. 如果偏大,那么下面的数就不用看了,向左移动
  2. 如果偏小,那么左边的数就不用看了,向下移动
  3. 这里注意一下边界
    算法 (七)矩阵相关:螺旋打印矩阵、旋转正方形矩阵、之字形打印矩阵、在行列都排好序的矩阵中找数

代码如下:

package cn.nupt;

/**
 * @Description: 在行列都排好序的矩阵中找数
 *
 * @author PizAn
 * @date 2019年2月17日 下午5:45:07 
 * 
 */
public class FindNumInSortedMatrix {
	

	public static boolean findNumInSortedMatrix(int[][] arr, int k) {
		int row = 0;
		int col = arr[0].length - 1;
		while (row <= arr.length - 1 && col >= 0) { //边界条件
			if (arr[row][col] == k) { //相等:直接返回
				return true;
			} else if (arr[row][col] > k) { //偏大:向左走
				col--; 
				} else {  //偏小,向下走
				row++;
			}

		}
		return false;
	}

}

相关文章: