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

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

lt. 867 转置矩阵

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

[思路分析]

  • 没啥可说的, 无非就是新建二维数组, 遍历原来的二维数组, 把原二维数组的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;
    }
}

补充一点, 对于非方阵(行于列不相等的矩阵), 我们不能用上面这种对角线两边交换的方法解决, 而是老老实实的去遍历原先的矩阵, 仍然是 Resji = Matrix ij;

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

[思路分析二, 两次二分查找]

在这里插入图片描述

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int rowIndex = binarySearchFirstColumn(matrix, target);
        if (rowIndex < 0) {
            return false;
        }
        return binarySearchRow(matrix[rowIndex], target);
    }

    public int binarySearchFirstColumn(int[][] matrix, int target) {
        int low = -1, high = matrix.length - 1;
        while (low < high) {
            int mid = (high - low + 1) / 2 + low;
            if (matrix[mid][0] <= target) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }
        return low;
    }

    public boolean binarySearchRow(int[] row, int target) {
        int low = 0, high = row.length - 1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            if (row[mid] == target) {
                return true;
            } else if (row[mid] > target) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return false;
    }
}

在这里插入图片描述

[思路分析三, 一次二分查找]

在这里插入图片描述

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length, n = matrix[0].length;
        int low = 0, high = m * n - 1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            int x = matrix[mid / n][mid % n];
            if (x < target) {
                low = mid + 1;
            } else if (x > target) {
                high = mid - 1;
            } else {
                return true;
            }
        }
        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;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值