蓝桥杯算法课《算法最美》笔记——4.多维数组和矩阵

4. 多维数组基础题

4.1 顺时针打印二维数组

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

[1 2 3 4

5 6 7 8

9 10 11 12

13 14 15 16]

打印1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10

思路:一圈一圈的打印。

import java.util.ArrayList;
import java.util.Arrays;

public class 顺时针打印2维数组 {
	public static void main(String[] args) {
		int[][] martix = {{1,2,3,4},
				         {5,6,7,8},
				         {9,10,11,12},
				        };
//		for(int[] i:martix) {
//			System.out.println(Arrays.toString(i));
//		}
		System.out.println(Arrays.toString(print(martix)));
	}
	
	public static int[] print(int[][] martix) {
		int leftUpRow = 0;  //行标初始值
		int leftUpCol = 0; //列标初始值
		int rightDownRow = martix.length -1; //行数
		int rightDownCol = martix[0].length - 1; //列数
		ArrayList<Integer> list = new ArrayList<Integer>();
		while (leftUpCol<rightDownCol && leftUpRow<rightDownRow) {
			int r = leftUpRow;
			int c=leftUpCol;
			while (c <= rightDownCol) {
				//上面一条边
				list.add(martix[r][c++]);
			}
			//回复
			c = rightDownCol;
			r++;
			//右面一条边
			while (r <= rightDownRow) {
				list.add(martix[r++][c]);
			}
			//恢复
			r = rightDownRow;
			c--;
			while (c >= leftUpCol) {
				list.add(martix[r][c--]);
			}
			//恢复
			r--;
			c = leftUpCol;
			while (r > leftUpRow) {
				list.add(martix[r--][c]);
			}
			//到小一维的数组
			leftUpCol++;
			leftUpRow++;
			rightDownCol--;
			rightDownRow--;
		}
		int[] arr = new int[list.size()];
		for(int i=0;i<list.size();i++) {
			arr[i] = list.get(i);
		}
		return arr;
	}
}

4.2 0所在的行列清零

题目:编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。

输入:
[[1,1,1],
[1,0,1],
[1,1,1]]
输出:
[[1,0,1],
[0,0,0],
[1,0,1]]

public static void setZeroes(int[][] matrix) {
    if(matrix.length==0){
        return;
    }
    int row=matrix.length;
    int col=matrix[0].length;
    // 标记需要清0的行的数组,需要清0则标记为1,默认是0
    int[] rowMark=new int[row];
    // 标记需要清0的列的数组,需要清0则标记为1,默认是0
    int[] colMark=new int[col];
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            if(matrix[i][j]==0){
                rowMark[i]=1;
                colMark[j]=1;
            }
        }
    }
    // 需要清0的行,所有行元素设置为0
    for (int i = 0; i <row ; i++) {
        if(rowMark[i]==1){
            for (int j = 0; j < col; j++) {
                matrix[i][j]=0;
            }
        }
    }
    // // 需要清0的列,所有列元素设置为0
    for (int i = 0; i <col ; i++) {
        if(colMark[i]==1){
            for (int j = 0; j < row; j++) {
                matrix[j][i]=0;
            }
        }
    }
}

4.3 z形打印二位数组

public class Z形打印二位数组{
	public static void main(String[] args) {
		int[][] arr = { 
				{ 1, 2, 3, 4 }, 
				{ 5, 6, 7, 8 }, 
				{ 9, 10, 11, 12 }, 
				{ 13, 14, 15, 16 } };

		print(arr);// 1 2 5 9 6 3 4 7 10 13 14 11 8 12 15 16 
	}

	/**
	 * Z形打印矩阵
	 * 
	 * @param arr
	 */
	static void print(int[][] arr) {
		int row = 0, col = 0;
		int maxRow = arr.length - 1, maxCol = arr[0].length - 1;

		boolean direct = true;// true: 箭头走上坡,false:箭头走下坡

		while (row <= maxRow && col <= maxCol) {
			if (direct) {// true: 箭头走上坡
				System.out.print(arr[row][col] + " ");
				if (row > 0 && col == maxCol) {// 竖向箭头向下
					direct = !direct;// 非横向箭头改为下坡方向
					row++;
					continue;
				} else if (row == 0 && col < maxCol) {// 横向箭头向右
					direct = !direct;// 非横向箭头改为下坡方向
					col++;
					continue;
				} else {// 非横竖向箭头走上坡方向
					row--;
					col++;
				}
			} else {// false:箭头走下坡
				System.out.print(arr[row][col] + " ");
				if (row == maxRow && col < maxCol) {// 横向箭头向右
					direct = !direct;// 非横向箭头改为上坡方向
					col++;
					continue;
				} else if (row < maxRow && col == 0) {// 竖向箭头向右
					direct = !direct;// 非横向箭头改为上坡方向
					row++;
					continue;
				} else {// 非横竖向箭头走下坡方向
					row++;
					col--;
				}
			}
		}
	}
}

4.4 边界为1的最大子方阵

class 边界为1的最大子方阵{
    public int largest1BorderedSquare(int[][] grid) {
		int result = 0;// 返回结果

		int rows = grid.length;// 总行数
		int cols = grid[0].length;// 总列数

		int[][] left = new int[rows][cols];
		int[][] up = new int[rows][cols];
		int[][] right = new int[rows][cols];
		int[][] down = new int[rows][cols];

		// 下面开始初始化4个数组
		// 左上
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				if (grid[i][j] == 1) {
					left[i][j] = j > 0 ? left[i][j - 1] + 1 : 1;
					up[i][j] = i > 0 ? up[i - 1][j] + 1 : 1;
				}
			}
		}
		// 右下
		for (int i = rows - 1; i >= 0; i--) {
			for (int j = cols - 1; j >= 0; j--) {
				if (grid[i][j] == 1) {
					right[i][j] = j < cols - 1 ? right[i][j + 1] + 1 : 1;
					down[i][j] = i < rows - 1 ? down[i + 1][j] + 1 : 1;
				}
			}
		}

		// 下面计算结果
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				int minOne = Integer.min(right[i][j], down[i][j]);
				for (; minOne > 0; minOne--) {
					int minTwo = Integer.min(left[i + minOne - 1][j + minOne - 1], up[i + minOne - 1][j                                + minOne - 1]);
					if (minOne <= minTwo) {
						result = Integer.max(result, minOne);
						break;
					}
				}
			}
		}
		return result * result;
	}
}

4.5 子数组最大累加和

class 子数组最大累加和 {
    public int maxSubArray(int[] nums) {
        int result = nums[0];
        for(int i = 1;i < nums.length;i++){
           nums[i] = nums[i] + Integer.max(nums[i - 1],0);
           result = Integer.max(result,nums[i]);
        }
        return result;
    }
}

4.6 子矩阵最大累加和

// N^3时间复杂度
private static int maxSum(int[][] matrix) {
  int beginRow = 0;// 以它为起始行

  final int M = matrix.length;
  final int N = matrix[0].length;

  int[] sums = new int[N];// 按列求和

  int max = 0;// 历史最大的子矩阵和

  while (beginRow < M) { // 起始行
    for (int i = beginRow; i < M; i++) {// 从起始行到第i行
      // 按列累加
      for (int j = 0; j < N; j++) {
        sums[j] += matrix[i][j];
      }
      //  累加完成
      //  求出sums的最大和子数组O(n)
      int t = Case05_MaxSubArray.findByDp(sums);
      if (t > max)
        max = t;
    }
    // 另起一行作为起始行.把sums清零
    Arrays.fill(sums, 0);// 快速地将sums的每个元素都设定为0
    beginRow++;
  }
  return max;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大果壳Clap

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值