算法--矩阵

一、知识点介绍

二、练习题目

        (1) 面试题 01.08. 零矩阵
        (2) 73. 矩阵置零
        (3) 1727. 重新排列后的最大子矩阵
        (4) 1034. 边界着色

三、算法思路

1. 面试题 01.08. 零矩阵

        (1) 遍历题目给的矩阵,记录下值为0的矩阵的横纵坐标;
        (2)再遍历一遍,把相应的列和行的元素置为0。

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        vector<int> column;
        vector<int> row;
        int i, j;
        for(i = 0; i < matrix.size(); ++i) {
            for(j = 0; j < matrix[i].size(); ++j) {
                if(matrix[i][j] == 0) {
                    column.push_back(i);
                    row.push_back(j);
                }
            }
        }
        for(i = 0; i < column.size(); ++i) {
            for(j = 0; j < matrix[column[i]].size(); ++j) {
                matrix[column[i]][j] = 0;
            }
        }
        for(i = 0; i < row.size(); ++i) {
            for(j = 0; j < matrix.size(); ++j) {
                matrix[j][row[i]] = 0;
            }
        }
    }
};

2. 矩阵置零

        (1) 跟上面那道题一样,copy过来就好了;
        (2) 也可以先复制一个跟原矩阵一样的矩阵temp。再遍历矩阵temp,找到为0的值,把题目给的矩阵的相应的行和列的值设置为0.

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        vector<int> column;
        vector<int> row;
        int i, j;
        for(i = 0; i < matrix.size(); ++i) {
            for(j = 0; j < matrix[i].size(); ++j) {
                if(matrix[i][j] == 0) {
                    column.push_back(i);
                    row.push_back(j);
                }
            }
        }
        for(i = 0; i < column.size(); ++i) {
            for(j = 0; j < matrix[column[i]].size(); ++j) {
                matrix[column[i]][j] = 0;
            }
        }
        for(i = 0; i < row.size(); ++i) {
            for(j = 0; j < matrix.size(); ++j) {
                matrix[j][row[i]] = 0;
            }
        }
    }
};

3. 重新排列后的最大子矩阵

预处理前
预处理后

ans

        (1) 先预处理数据,具体做法是:把每一行都当作水平线,统计向上衍生的值为1的方块的个数
        (2) 然后再把每一列的个数赋值给新的数组,并且对数组的大小进行升序排序
        (3) 当j指到某一点的时候,如第三张图所示,最大面积为蓝色框住的面积,再更新ans的值,并返回。

class Solution {
public:
    int largestSubmatrix(vector<vector<int>>& matrix) {
        int row = matrix.size();
        int col = matrix[0].size();
        int i, j, ans = 0;
        int vline[100010];
        int tvline[100010];
        memset(vline, 0, sizeof(vline));
        for(i = 0; i < row; ++i) {
            for(j = 0; j < col; ++j) {
                if(matrix[i][j] == 0) {
                    vline[j] = 0;
                } else {
                    vline[j]++;
                }
            }

            for(j = 0; j < col; ++j) {
                tvline[j] = vline[j];
            }

            sort(tvline, tvline+col);

            for(j = 0; j < col; ++j) {
                ans = max(ans, tvline[j]*(col-j));
            }
        }
        return ans;
    }
};

4. 边界着色

        (1) 这道题是关于深度优先搜索的。
        (2) 题目已经给了搜索起点,就是grid[row][col], 从起点开始递归搜索,确定哪些是连通的点。并用一个hash数组进行标记。
        (3) 有四个方向,通过加上dir的值,改变点的位置。
        (4) 递归搜索,首先要确定递归边界:1. 超过矩阵边界要返回; 2. 已经被标记的要返回; 3. 和上一个连通点的颜色不一样的话要返回。
        (5) 通过第(4)步就很好确定要递归哪些元素,也就是dfs函数里面有哪些参数需要传输。分别是矩阵本身,矩阵的长宽的值,点的起始位置的坐标,上一个点的颜色。
        (6) 深搜完成之后,要改变连通的面积的边界的点的颜色为color。所以要遍历整个矩阵,当一个点的下一步是矩阵的边界,或者是没有在深搜的时候被标记的点,那么这个点就是边界。更新该点的值,并返回矩阵。

class Solution {
    int hash[55][55];
    int dir[4][2] = {
        {0, 1},
        {0, -1},
        {1, 0},
        {-1, 0}
    };
    void dfs(vector<vector<int>>& grid, int m, int n, int row, int col, int precolor) {
    	//递归边界
        if(row < 0 || col < 0 || row == m || col == n || hash[row][col] == 1) {
            return;
        }
        if(grid[row][col] != precolor) {
            return;
        }
        //标记
        hash[row][col] = 1;
        for(int k = 0; k < 4; ++k) {
            int xk = row + dir[k][0];
            int yk = col + dir[k][1];
            dfs(grid, m, n, xk, yk, grid[row][col]);
        }
    }
public:
    vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
        int m = grid.size();
        int n = grid[0].size();
        memset(hash, 0, sizeof(hash));
        dfs(grid, m, n, row, col, grid[row][col]);
        vector<vector<int>> temp(grid);
        int i, j, k;
        for(i = 0; i < m; ++i) {
            for(j = 0; j < n; ++j) {
            	//如果没有被标记,就直接跳过
                if(hash[i][j] == 0) continue;
                temp[i][j] = grid[i][j];
                //如果下一步会出界,就说明是边界,就改变color
                for(k = 0; k < 4; ++k) {
                    int xi = i + dir[k][0];
                    int yj = j + dir[k][1];
                    if(xi < 0 || yj < 0||xi == m || yj == n || hash[xi][yj] == 0) {
                        temp[i][j] = color;
                    }
                }
            }
        }
        return temp;
    }
};

四、 总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值