4. <tag-数组模拟矩阵>-lt.967 转置矩阵 + lt.54-螺旋矩阵 + lt.74-搜索二维矩阵 + 剑指Offer.29-顺时针打印矩阵

一, 数组和矩阵结合的问题

lt. 967 转置矩阵

[案例需求]
在这里插入图片描述

[思路分析]

  • 没啥可说的, 无非就是新建二维数组, 遍历原来的二维数组, 把原二维数组的arr[行,列]放到新二维数组的arr_new[列,行]中去;
  • 在实现过程中需要注意的一点: 在矩阵的转置过程中, 外层是遍历行, 内层是遍历列, 那么在内循环遍历列时, 我们遍历到哪里结束呢? 对角线处! j可以从0到i(下对角线), 也可以从 i到 arr.length-1(上对线);
    [代码实现]
class Solution {
    
    
    public int[][] transpose(int[][] matrix) {
    
    
        //
        int[][] res = new int[matrix[0].length][matrix.length];


        for(int i = 0; i < matrix.length; i++){
    
    
            for(int j = i; j < matrix[i].length; j++){
    
    
                res[j][i] = matrix[i][j];
            }
        }

        return res;
    }
}

lt.54 螺旋矩阵

[案例需求]
在这里插入图片描述在这里插入图片描述
[思路分析]

  • 数组和矩阵一起结合考察(用数组模拟矩阵), 偏数学思想, 机器学习领域考察那是相当的多, 管咱屁事哈哈, 既然遇到了, 就把考察频度高的几道题甩出来
  1. 螺旋矩阵,即顺时针读取矩阵, 记录到结果集合中并返回,
  2. 我们最常用的解法就是, 记录矩阵的四个角, 不断的缩小角之间的范围, 直到目标数组中只剩下单纯的一列或一行数据, 甚至就剩一个数字, 同时也要记得把每次遍历的两个角之间的数, 添加到用于返回的集合中;
  3. 看上图最下面的提示, 矩阵是不为空的, 所以数组不会为空, 我们也不需要加什么特例条件了;
  4. 我们用left和right, 来记录每次左右遍历矩阵的左角和右角, 所以很显然, 从左向右遍历就是从left–>right遍历数组, 从右向左遍历就是从right–>left遍历数组;
  5. 我们用top和bottom,来记录每次上下遍历矩阵的上角和下角, 所以也很显然, 从上到下遍历就是从top–>bottom遍历数组, 从下到上遍历就是从bottom–>top遍历数组;
  6. 旋转跳跃我闭眼, 当我们左->右, 上->下, 右->左, 下->上遍历到矩阵只剩下一行或者一列,或者一个数字的时候, 再来一次顺序循环, 添加进集合, 就大功告成了 在这里插入图片描述
  • 参考文章:

[代码实现]

class Solution {
    
    
    public List<Integer> spiralOrder(int[][] matrix) {
    
    
        //定义四个角
        // top --> bottom 是从上往下遍历
        // left --> right 是从左往右遍历
        int top = 0;    //top指明哪一行的行首
        int bottom = matrix.length - 1; //bottom 指明哪一行的数目
        int left = 0;   //left指明哪一列的列首
        int right = matrix[0].length - 1; //right指明哪一列

        //特例(无,)因为题目给了:     1 <= matrix.length <= 10
        //
        //结果集合
        List<Integer> list = new ArrayList<>();

        while(top < bottom && left < right){
    
    
            //从左到右遍历, 放入list
            for(int i = left; i < right; i++){
    
    list.add(matrix[top][i]);} //当前top行的每一列
            for(int i = top; i < bottom; i++){
    
    list.add(matrix[i][right]);} //当前right列的每一行
            for(int i = right; i > left; i--){
    
    list.add(matrix[bottom][i]);} //当前bottom行的每一列
            for(int i = bottom; i > top; i--){
    
    list.add(matrix[i][left]);} //当前left列的每一行

            ++left;
            --right;
            ++top;
            --bottom;
        }

        //边缘判断(当只剩下了一行. 或者一列, 或者一个数, 直接一次遍历加入集合即可)
        //只剩下顺序一行
        if(bottom == top){
    
    
            for(int i = left; i <=right; i++){
    
    list.add(matrix[top][i]);}
        }else if (left == right){
    
    
            for(int i = top; i <= bottom; i++){
    
    list.add(matrix[i][left]);}
        }
        return list;   
    }
}

lt.74-搜索二维矩阵

[案例需求]
在这里插入图片描述
在这里插入图片描述

[思路分析]

  • 本题主要是考察二分查找, 但我们先贴一个简单的写法: 倒序遍历;
  1. 因为给定的matrix矩阵是由左到右, 由上到下递增的, 所以我们理应能够想到从每行倒序往下遍历,
    • 如果目标数>本行的最后一个数, 直接跳过本行;
    • 如果目标数 < 本行的最后一个数, 就倒序往左遍历本行, 找到就直接返回, 发现有目标数> 当前数的, 直接跳出本行遍历, 继续下行的遍历
      [代码实现]

解法一: 倒序遍历

class Solution {
    
    
    public boolean searchMatrix(int[][] matrix, int target) {
    
    
        //解法一, 倒序遍历
        //从矩阵的右端开始遍历:
        //1. 遍历数 < 当前数, 跳到下一行进行遍历;
        //2. 遍历数 > 当前述, 本行内往前进行遍历(倒序遍历)
        //3. 遍历数 == 当前数, 直接return true;

        //外层循环控制二维数组中的每个一维数组, 内层循环控制一维数组中的每个数
        for(int i = 0; i < matrix.length; i++){
    
    
            //二维数组中的每个数组的最后一个数的下标;
            int last = matrix[i].length - 1;
           
            for(int j = last; j >=0; j--){
    
    
                if(target == matrix[i][j]) return true;

                if(target > matrix[i][j]) continue;
            }
        }
        return false;
    }
}

解法二, 二分查找法:

[待补充]

剑指Offer.29-顺时针打印矩阵

[案例需求]
在这里插入图片描述

[思路分析]

  • 解题思路跟 lt54. 螺旋矩阵完全相同, 只不过最后返回的是一个int类型的数组, 如果我们前面用的是list存储的话, 还需要把list数组转换为int类型的数组;
  • 在这里要特别注意: List<Integer> 是不能直接转换为 int[] 数组的, 使用 list.toAarry(int[]) 也不行! —> 补充文章
    [代码实现]
class Solution {
    
    
    public int[] spiralOrder(int[][] matrix) {
    
    

        //特例
        if(matrix.length == 0 || matrix[0].length == 0) return new int[]{
    
    };
        //记录四个角, 由左向右打印, 由上到下打印, 由右向做打印, 由下向上打印;
        // left和right控制列, top和bottom控制行
        int left = 0;
        int right = matrix[0].length - 1;
        int top = 0;
        int bottom = matrix.length - 1;

        //集合, 到最后会返回数组(集合->数组)
        List<Integer> list = new ArrayList<>();

        while(left < right && top < bottom){
    
    
            for(int i  = left; i < right; i++){
    
    list.add(matrix[top][i]);}
            for(int i = top; i < bottom; i++){
    
    list.add(matrix[i][right]);}
            for(int i = right; i > left; i--){
    
    list.add(matrix[bottom][i]);}
            for(int i = bottom; i > top; i--){
    
    list.add(matrix[i][left]);}

            ++left;
            --right;
            ++top;
            --bottom;
        }

        //仅剩下一行了
        if(bottom == top){
    
    
            for(int i = left; i <= right; i++){
    
    
                list.add(matrix[top][i]);
            }//仅剩下一列了
        }else if(left == right){
    
    
            for(int i = top; i <=bottom; i++){
    
    
                list.add(matrix[i][left]);
            }
        }
         int[] arr = list.stream().mapToInt(Integer::valueOf).toArray();
    
        return arr;
    }
}

猜你喜欢

转载自blog.csdn.net/nmsLLCSDN/article/details/121284683
今日推荐