• 算法很美 笔记 4.多维数组与矩阵


    4.多维数组与矩阵

    题1 :顺时针打印二维数组

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

    示例 1:

    输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
    输出:[1,2,3,6,9,8,7,4,5]
    示例 2:

    输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
    输出:[1,2,3,4,8,12,11,10,9,5,6,7]

    限制:

    0 <= matrix.length <= 100
    0 <= matrix[i].length <= 100

    public int[] spiralOrder(int[][] matrix) {
        int[] result =new int[]{};
        if(matrix.length==0){
            return result;
        }
        int leftUpRow=0,leftUpCol=0,rightDownRow=matrix.length-1,rightDownCol=matrix[0].length-1;
        result=new int[matrix.length*matrix[0].length];
        int index=0;
        if(matrix==null){
            return result;
        }
        while(leftUpCol<=rightDownCol&&leftUpRow<=rightDownRow){
            //打印第一行
            int row=leftUpRow,col=leftUpCol;
            while(index<result.length&&col<=rightDownCol){//上
                result[index++]=matrix[row][col++];
            }
            //恢复
            col=rightDownCol;
            row++;
            while(index<result.length&&row<=rightDownRow){//右
                result[index++]=matrix[row++][col];
            }
            row=rightDownRow;
            col--;
            while(index<result.length&&col>=leftUpCol){//下
                result[index++]=matrix[row][col--];
            }
            col=leftUpCol; 
            row--;
            while(index<result.length&&row>leftUpRow){//左
                result[index++]=matrix[row--][col];
            }
    
            leftUpCol++;
            leftUpRow++;
            rightDownCol--;
            rightDownRow--;
        }
        return  result;
    }
    

    逻辑清楚,起名知道意思,写一步测一步

    题目链接

    题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;
        int[] rowMark=new int[row];
        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;
                }
            }
        }
        for (int i = 0; i <row ; i++) {
            if(rowMark[i]==1){
                for (int j = 0; j < col; j++) {
                    matrix[i][j]=0;
                }
            }
        }
        for (int i = 0; i <col ; i++) {
            if(colMark[i]==1){
                for (int j = 0; j < row; j++) {
                    matrix[j][i]=0;
                }
            }
        }
    }
    

    题目链接

    题3:z形打印二位数组

    在这里插入图片描述

    public class Case03_PrintMatrixZig {
      public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            // {13, 14, 15, 16},
        };
        print(matrix);
      }
    
      static void print(int[][] matrix) {
        int r = 0, m = matrix.length;
        int c = 0, n = matrix[0].length;
        boolean l2r = true;//从左到右
        while (r < m && c < n) {
          //从左下到右上的斜线
          if (l2r) {
            System.out.print(matrix[r][c] + " ");
            //现在在第一行,列未到边界,这是只能向右走
            if (r == 0 && c < n - 1) {
              l2r = !l2r;//方向切换
              c++;
              continue;
            } else if (r > 0 && c == n - 1) {//现在在最后一列,只能向下走
              l2r = !l2r;
              r++;
              continue;
            } else {//继续走上坡
              r--;
              c++;
            }
          } else {//反,走下坡
            System.out.print(matrix[r][c] + " ");
            if (c == 0 && r < m - 1) {//走到第一列,只能往下走
              l2r = !l2r;
              r++;
              continue;
            } else if (r == m - 1) {//到最后一行,只能往右走
              l2r = !l2r;
              c++;
              continue;
            } else {
              r++;
              c--;
            }
          }
        }
      } 
    }
    

    题4:边界为1的最大子方阵

    给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0。

    示例 1:

    输入:grid = [[1,1,1],[1,0,1],[1,1,1]]
    输出:9
    示例 2:

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

    提示:1 <= grid.length <= 100
    1 <= grid[0].length <= 100

    public static int largest1BorderedSquare(int[][] grid) {
        if(grid.length==0){
            return 0;
        }
        if(grid.length==1){
            for (int i = 0; i < grid[0].length; i++) {
                if(grid[0][i]==1){
                    return 1;
                }
            }
            return 0;
        }
        int row=grid.length,col=grid[0].length;
        int N=Math.min(row,col);
        for (; N>=1 ; N--) {
            for (int i = 0; i <=row-N; i++) {
                c1:for (int j = 0; j<=col-N ; j++) {
                    int r=i,c=j;
                    while(c<N+j){//up
                        if(grid[r][c++]==0){
                            continue c1;
                        }
                    }
                    c--;
                    while(r<N+i){//right
                        if(grid[r++][c]==0){
                            continue c1;
                        }
                    }
                    r--;
                    while(c>=j){//down
                        if(grid[r][c--]==0){
                            continue c1;
                        }
                    }
                    c++;
                    while(r>=i){//left
                        if(grid[r--][c]==0){
                            continue c1;
                        }
                    }
                    r++;
                    return N*N;
                }
            }
        }
        return 0;//{0,0},{0,0}这种情况下执行
    }
    
    public static int largest1BorderedSquare(int[][] grid) {
        int row = grid.length;
        int col = grid[0].length;
    
        // initial
        int[][] rowOnes = new int[row][col]; // rowOnes[i][j] = (i,j) 右边连续的 1 数目; 包括 (i,j)
        int[][] colOnes = new int[row][col]; // colOnes[i][j] = (i,j) 下边连续的 1 数目; 包括 (i,j)
        for (int i = 0; i < row; i++) {//最后一列,右边连续数是1则为1
            rowOnes[i][col - 1] = (grid[i][col - 1] == 1 ? 1 : 0);
        }
        for (int i = 0; i < col; i++) {//最后一行,下边连续是1则是1
            colOnes[row - 1][i] = (grid[row - 1][i] == 1 ? 1 : 0);
        }
        // iteration
        for (int i = 0; i <row; i++) {//逐行
            for (int j = col - 2; j >= 0; j--) {//从倒数第二列往左
                rowOnes[i][j] = (grid[i][j] == 1 ? (rowOnes[i][j + 1] + 1) : 0);//若为1则,右边连续数位右边元素连续数加1
            }
        }
        for (int i = row - 2; i >= 0; i--) {//从倒数第二行往上
            for (int j =0; j <col; j++) {//逐列
                colOnes[i][j] = (grid[i][j] == 1 ? (colOnes[i + 1][j] + 1) : 0);//若为1则,向下连续数位下边元素连续数加1
            }
        }
        int max = 0;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                for (int m = Math.min(rowOnes[i][j], colOnes[i][j]); m > max; m--) {
                    if(colOnes[i][j + m - 1] >= m && rowOnes[i + m - 1][j] >= m) {
                        max = Math.max(max, m);
                        break;
                    }
                }
            }
        }
        return max * max;
        //        for(int N=Math.min(row,col);N>=1;N--) {
        //            for (int i = 0; i <= row-N; i++) {
        //                for (int j = 0; j <= col-N; j++) {
        //                    if(rowOnes[i][j]>=N&&colOnes[i][j]>=N&&rowOnes[i+N-1][j]>=N&&colOnes[i][j+N-1]>=N){
        //                        return N*N;
        //                    }
        //                }
        //            }
        //        }
        //        return 0;
    }
    

    题目链接

    题5 :子数组最大累加和

    • 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

      示例:

      输入: [-2,1,-3,4,-1,2,1,-5,4],
      输出: 6
      解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
      进阶:

      如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

       // 暴力法破解 Θ(n²)
        static void findByForce(int[] arr) {
          int maxSum = arr[0];
      
          for (int j = 0; j < arr.length; j++) {
            int sum = arr[j];// 某个元素为子数组的第一个元素
            int maxOfJ = sum;
      
            for (int i = j + 1; i < arr.length; i++) {
              sum += arr[i];// 累加后续元素
              if (sum > maxOfJ) {
                maxOfJ = sum;
              }
            }
            if (maxOfJ > maxSum) {
              maxSum = maxOfJ;
            }
          }
          System.out.println(maxSum);
        }
      
        // 递推法 Θ(n)
      //如果左边的元素是负的就舍弃
        static int findByDp(int[] arr) {
          // System.out.println("======="+arr.length);
          if (arr.length == 0) return 0;
          int sumJ = arr[0];  // 前J个元素的最大贡献
          int max = sumJ;
          int left = 0, right = 0;
          for (int j = 1; j < arr.length; j++) {
            if (sumJ >= 0) {  // 左子表的最大和为正,继续向后累加
              sumJ += arr[j];
            } else {
              sumJ = arr[j];
              left = j;//丢弃前部分和的同时,更新left
            }
      
            if (sumJ > max) {
              max = sumJ;
              right = j;//更新max的同时更新right
            }
          }
          // System.out.println(max+",left="+left+",right:"+right);
          return max;
        }
      

    题目链接

    题6 :子矩阵最大累加和

    • 给定一-个矩阵matrix ,其中的值有正、有负、有0 ,返回子矩阵的最大累加和。

    • 例如, matrix为:

    -1 -1 -1
    -1 2 2
    -1 -1 -1

    其中最大累加和的子矩阵为:
    2 2
    所以返回4

    //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;
    }
    

    一、矩阵的加法与减法

    1. 运算规则

    在这里插入图片描述

    简言之,两个矩阵相加减,即它们相同位置的元素相加减!
    注意:只有对于两个行数、列数分别相等的矩阵(即同型矩阵),加减法运算才有意义,即加减运算是可行的.

    1. 运算性质(假设运算都是可行的)
      满足交换律和结合律
      交换律A+B= B+A;
      结合律(A+B)+C= A+(B+C).

    二、矩阵与数的乘法

    1. 运算规则
      数入乘矩阵λ,就是将数λ乘矩阵A中的每一个元素,记为λA或Aλ.
      特别地,称- A称为A=(aij)m xs的负矩阵。

    2. 运算性质
      满足结合律和分配律
      结合律: (λu)A=λ(μA); (λ+μ)A =λA+μA.
      分配律: λ (A+B)=λA+λB.

    三、矩阵与矩阵的乘法

    1、运算规则
    设A=(aij)mxs,B=(bij) sxn,则A与B的乘积C =AB是这样一一个矩阵 : .
    (1)行数与(左矩阵) A相同,列数与(右矩阵) B相同,即C =(cij)mxn.
    (2) C的第i行第j列的元素Cq由A的第i行元素与B的第j列元素对应相乘,再取乘积之和.
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    /**
     *   矩阵乘法
     *   矩阵1为n*m矩阵,矩阵2为m*p矩阵
     *   结果为n*p矩阵
     */
    public static long[][] matrixMultiply(long[][] m1, long[][] m2) {
      final int n = m1.length;
      final int m = m1[0].length;
      if (m != m2.length) throw new IllegalArgumentException();
      final int p = m2[0].length;
    
      long[][] result = new long[n][p];// 新矩阵的行数为m1的行数,列数为m2的列数
    
      for (int i = 0; i < n; i++) {//m1的每一行
        for (int j = 0; j < p; j++) {//m2的每一列
          for (int k = 0; k < m; k++) {
            result[i][j] += m1[i][k] * m2[k][j];
          }
        }
      }
      return result;
    }
    
  • 相关阅读:
    golang基础之第一个go程序
    golang基础之工程结构
    golang基础之初识
    Prometheus神器之监控K8s集群
    Kubernetes使用GlusterFS实现数据持久化
    Go使用Makefile构建
    快排的2种分区图解
    密钥交换之DH算法
    go mod使用
    socket常见选项之SO_REUSEADDR,SO_REUSEPORT
  • 原文地址:https://www.cnblogs.com/cxynb/p/12527646.html
Copyright © 2020-2023  润新知