算法零基础100-3

前言

        
欢迎大家关注我的公众号:菜鸡哪里出来,以获取更多资讯


        今天算法的内容是:矩阵


        本题解旨在用通俗易懂的语言来讲解课后作业中的难题,简单题会略过

题解对应章节

算法零基础100讲(英雄哥著)–第三讲

第一题:1582. 二进制矩阵中的特殊位置

难度 : ★★

题目描述


        给你一个大小为 rows x cols 的矩阵 mat,其中 mat[i][j] 是 0 或 1,请返回 矩阵 mat 中特殊位置的数目 。

        
特殊位置的定义:如果 mat[i][j] == 1 并且第 i 行和第 j 列中的所有其他元素均为 0(行和列的下标均 从 0 开始 ),则位置 (i, j) 被称为特殊位置

算法思路


        总体思路:简单的模拟问题,根据题目要求进行穷举即可。

        具体来说,就是以如下三个条件进行筛选:①特殊位置的元素具备该行所有元素之和为1②该列所有元素之和为1③该元素为1

源码剖析

class Solution {
public:
    int numSpecial(vector<vector<int>>& mat) {
        int rows = mat.size();
        int cols = mat[0].size();
        int res=0;
        vector<int> col(cols),row(rows);
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                row[i] += mat[i][j]; //求每个元素所在每行之和
                col[j] += mat[i][j]; //求每个元素所在每列之和
            }
        }
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                if ((mat[i][j]==1) && (row[i]==1) && (col[j] == 1))//进行筛选
                {
                    res++;
                }
                
            }
            
        }
        return res;

    }
};

第二题:48. 旋转图像

难度 : ★★

题目描述

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

算法思路


        相信去看这个题目官方题解和高赞题解的小伙伴,肯定会疑惑于什么逐层平移,什么变换公式,难记忆不说,看懂都很费劲。但其实有简单的线性代数基础就可以轻松秒杀,还能得出通用结论

        观察所给的测试样例不难观察出如下的结论

矩阵顺时针旋转90° == 矩阵先进行转置,后进行水平翻转

源码剖析

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int rows = matrix.size();
        int cols = matrix[0].size();
        //矩阵转置,旋转90°等于先转置再水平翻转
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < i; j++) //①
            {
                int tmp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = tmp;
            }
        }
        //矩阵水平翻转
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < (cols+1)/2; j++) //②
            {
                int tmp = matrix[i][j];
                matrix[i][j] = matrix[i][cols - 1 -j];
                matrix[i][cols - 1 -j] = tmp;
            }
        }       
    }
};
  • 1、第一处注释要特意注意列的上界,因为矩阵转置是行变列,列变行。

            故转置可进一步细化为,矩阵各元素沿主对角线翻转,所以只需要进行矩阵下三角翻转到上三角即可(对于方阵)

  • 2、为①③条件的实现

第三题:867. 转置矩阵

难度 : ★★

题目描述

给你一个二维整数数组 matrix, 返回 matrix 的 转置矩阵 。
矩阵的 转置 是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。

算法思路


        本题给予另一种转置的思路,在没有限定必须原地转置的情况下,构造一个新矩阵也为一种特别简单的方法,当然要注意此时的ij范围。

源码剖析

class Solution {
public:
    vector<vector<int>> transpose(vector<vector<int>>& matrix) {      
        vector<vector<int>> res(matrix[0].size(),vector<int>(matrix.size()));
        for (int i = 0; i < matrix.size(); i++)
        {
            for (int j = 0; j <matrix[0].size(); j++)//①
            {
                res[j][i] = matrix[i][j];
            }
            
        }
        return res;

    }
};
  • 1、此处因为是新矩阵填数,所以j上界为矩阵的列数

第四题:1886. 判断矩阵经轮转后是否一致

难度 : ★★

题目描述

给你两个大小为 n x n 的二进制矩阵 mat 和 target 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false 。

算法思路


        本题应用第二题的结论进行矩阵90°旋转,显然可知,一个矩阵旋转4次后就会恢复原样;故四次旋转内能相等即复合要求,否则返回false

源码剖析

cpp
class Solution {
public:
    bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
        bool res =false;
        for (int k = 0; k < 4; k++)
        {
            for (int i = 0; i < mat.size(); i++)
            {
                for (int j = 0; j < i; j++)
                {
                    swap(mat[i][j],mat[j][i]);
                }
            }
            for (int i = 0; i < mat.size(); i++)
            {
                for (int j = 0; j < (mat[0].size()+1)/2; j++)
                {
                    swap(mat[i][j],mat[i][mat[0].size()-j-1]);
                }
            }
            if (mat == target)
            {
                res = true;
                break;
            }
            
        }
        return res;

    }
};class Solution {
public:
    bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
        bool res =false;
        for (int k = 0; k < 4; k++)//①
        {
            for (int i = 0; i < mat.size(); i++)//②
            {
                for (int j = 0; j < i; j++)
                {
                    swap(mat[i][j],mat[j][i]);
                }
            }
            for (int i = 0; i < mat.size(); i++)//③
            {
                for (int j = 0; j < (mat[0].size()+1)/2; j++)
                {
                    swap(mat[i][j],mat[i][mat[0].size()-j-1]);
                }
            }
            if (mat == target)//④
            {
                res = true;
                break;
            }
            
        }
        return res;

    }
};
  • 1、循环模拟四次旋转
  • 2、进行矩阵转置
  • 3、进行水平翻转,完成一次90°旋转
  • 4、若相等则退出循环,返回值

第五题:1260. 二维网格迁移

难度 : ★★

题目描述


        给你一个 m 行 n 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。

        每次「迁移」操作将会引发下述活动:

        位于 grid[i][j] 的元素将会移动到 grid[i][j + 1]。

        位于 grid[i][n - 1] 的元素将会移动到 grid[i + 1][0]。

        位于 grid[m - 1][n - 1] 的元素将会移动到 grid[0][0]。

        请你返回 k 次迁移操作后最终得到的 二维网格。

算法思路


        本题是一个简单的模拟问题,即从后往前进行交换矩阵每一列,再从下往上交换第一列的元素

源码剖析

class Solution {
public:
    vector<vector<int>> shiftGrid(vector<vector<int>>& grid, int k) {
        for (int i = 0; i < k; i++)  //①
        {
            for (int i = 0; i < grid.size(); i++)
            {
                for (int j = grid[0].size()-1; j >0; j--)//②
                {               
                    swap(grid[i][j-1],grid[i][j]);
                }
            }
            for (int i = grid.size()-1; i >0 ; i--)//③
            {
                swap(grid[i][0],grid[i-1][0]);
            }            
        }
        return grid;

    }
};
  • 1、变换k次迁移
  • 2、从后往前进行变换每一列
  • 3、从下往上交换第一列的元素

第六题:1260. 二维网格迁移

难度 : ★★★

题目描述


        本章节的压轴题来啦!

        给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

算法思路


        首先设定上下左右边界

        其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界

        判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案

        若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理

        不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案

源码剖析

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        if (matrix.size() == 0)
        {
            return res;
        }
        int upper =0,down = matrix.size()-1,left =0,right = matrix[0].size()-1;
        while (true)
        {
            for (int i = left; i <= right; i++)
            {
                res.push_back(matrix[upper][i]);
            }
            if (++upper > down)
            {
                break;
            }
            for (int i = upper; i <= down; i++)
            {
                res.push_back(matrix[i][right]);
            }
            if (--right < left)
            {
                break;
            }
            for (int i = right; i >= left ; i--)
            {
                res.push_back(matrix[down][i]);
            }
            if (--down <  upper)
            {
                break;
            }
            for (int i = down; i >= upper;i--)
            {
                res.push_back(matrix[i][left]);
            }
            if (++left > right)
            {
                break;
            }       
        }
        return res;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值