力扣刷题攻略数组篇-二维数组及滚动数组(二)


文章内容是自己刷leetcode官方刷题攻略的一些经验与总结。
题目链接详见 leetcode刷题攻略
如果喜欢的话,别忘了点个赞哦 ^ _ ^

一.661图片平滑器

1.题目描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

这道题目其实和计算机视觉里的kernel为3*3的均值滤波器类似。

当然不清楚均值滤波器也没关系。我们分析发现需要根据题目提供的矩阵来构造一个新矩阵,那么新矩阵的每个元素是怎么得到的呢?

新矩阵的每个元素与原矩阵对应位置及其周围8个单元格有关。有下面几种情况:

  • 情况一:原矩阵周围8个单元格都有数值,也就是这8个单元格在原始矩阵边界范围内。这种情况下新矩阵的值就是原始矩阵对应位置的值及其周围8个单元格的值的和再除以9。
  • 情况二:原矩阵周围8个单元格部分没有数值,也就是8个单元格中一部分在矩阵的边界内,一部分超出了矩阵的边界,这种情况下,新矩阵的值就是原始矩阵对应位置的值以及周围8个单元格中在边界范围内的单元格的值的和除以有效单元格的个数。

我们可以用num来统计有效单元格的个数,sum来统计有效单元格的数值和

C++代码如下:

class Solution {
public:
    vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
        //类似计算机视觉里面的均值滤波器,kernel为3*3
        //遍历,判断边界就行

        int m = img.size();
        int n = img[0].size();
        vector<vector<int>> ans(m, vector<int>(n, 0));
        for(int i = 0; i < m; i ++) {
            for(int j = 0; j < n; j ++) {
                int num = 0, sum = 0;
                for(int x = i - 1; x <= i + 1; x ++) {
                    for(int y = j - 1; y <= j + 1; y ++) {
                        if(x >= 0 && x < m && y >= 0 && y < n) {
                            num ++;
                            sum += img[x][y];
                        }
                    }
                }
                ans[i][j] = sum / num;
            }
        }

        return ans;
    }
};

二.598范围求和II

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

我们直接可以想到的方法是,先用题目提供的ops矩阵来把原始矩阵处理一遍,然后再次遍历处理后的矩阵,用maxNum来记录最大值,cnt记录最大值出现的个数。

C++ 代码如下:

class Solution {
public:
    int maxCount(int m, int n, vector<vector<int>>& ops) {
        //1.先根据ops处理矩阵
        //2.再找最大整数个数

        vector<vector<int>> matrix(m, vector<int>(n, 0));
        for(int i = 0; i < ops.size(); i ++) {
            int x = ops[i][0], y = ops[i][1];
            for(int p = 0; p < x; p ++) {
                for(int q = 0; q < y; q ++) {
                    matrix[p][q] ++;
                }
            }
        }

        int cnt = 0, maxNum = 0;
        for(int i = 0; i < m; i ++) {
            for(int j = 0; j < n; j ++) {
                if(matrix[i][j] == maxNum) {
                    cnt ++;
                } else if(matrix[i][j] > maxNum) {
                    cnt = 1;
                    maxNum = matrix[i][j];
                }
            }
        }

        return cnt;
    }
};

很可惜,上述暴力的做法会超时

在这里插入图片描述
我们可以分析一下时间复杂度,主要有两个大循环,那么就是取二者最大值。

第一个大循环最差情况为 ops 长度 * ops[i] 中每个元素的最大值。
所以时间复杂度为O(m * n * ops.length)。

第二个大循环为O(m * n)

那么显然第一个循环时间更长。

这道题其实我们可以转换思路:
矩阵中的数是通过ops二维数组才增加的,寻找矩阵中的最大整数,就是寻找哪些位置被操作的次数最多,也就是寻找ops数组中最小的两个ai,bi的乘积

C++ 代码如下:

class Solution {
public:
    int maxCount(int m, int n, vector<vector<int>>& ops) {
        //1.先根据ops处理矩阵
        //2.再找最大整数个数
        //很可惜,上述做法会超时

        //转换思路
        //矩阵中的数是通过ops二维数组才增加的,寻找矩阵中的最大整数,就是寻找哪些位置被操作的次数最多,也就是寻找ops数组中最小的两个ai,bi的乘积


        //转换思路
        int minm = m, minn = n;
        for(int i = 0; i < ops.size(); i ++) {
            minm = min(minm, ops[i][0]);
            minn = min(minn, ops[i][1]);
        }

        return minm * minn;


        //超时方法
        // vector<vector<int>> matrix(m, vector<int>(n, 0));
        // for(int i = 0; i < ops.size(); i ++) {
        //     int x = ops[i][0], y = ops[i][1];
        //     for(int p = 0; p < x; p ++) {
        //         for(int q = 0; q < y; q ++) {
        //             matrix[p][q] ++;
        //         }
        //     }
        // }

        // int cnt = 0, maxNum = 0;
        // for(int i = 0; i < m; i ++) {
        //     for(int j = 0; j < n; j ++) {
        //         if(matrix[i][j] == maxNum) {
        //             cnt ++;
        //         } else if(matrix[i][j] > maxNum) {
        //             cnt = 1;
        //             maxNum = matrix[i][j];
        //         }
        //     }
        // }

        // return cnt;


    }
};

三.419甲板上的战舰

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

这道题目中文翻译可能有歧义。
按照英文翻译,紧挨着的战舰battleship应该算作一个ships,我们最终需要统计ships的数量而不是battleship的数量
在这里插入图片描述

1.解法一:更改 ‘X’ 为 ‘.’

遍历board遇到battleship就把与它在一个ships的battleship全变为 ‘.’,更新答案。

时间复杂度O(m * n * max(m,n))

C++ 代码如下:

class Solution {
public:
    int countBattleships(vector<vector<char>>& board) {
        //题目可能有歧义
        //按照英文翻译,紧挨着的战舰battleship应该算作一个ships,统计ships的数量

        int ans = 0;
        int m = board.size();
        int n = board[0].size();
        for(int i = 0 ; i < m; i ++) {
            for(int j = 0; j < n; j ++) {
                if(board[i][j] == 'X') {
                    ans ++;
                    board[i][j] = '.';
                    for(int k = i + 1; k < m && board[k][j] == 'X'; k ++) {
                        board[k][j] = '.';
                    }

                    for(int k = j + 1; k < n && board[i][k] == 'X'; k ++) {
                        board[i][k] = '.';
                    }
                }
            }
        }

        return ans;
    }
};
2.解法二:实现一次扫描算法,并只使用 O(1) 额外空间,并且不修改 board 的值

枚举起点,只在X刚出现的位置统计个数,枚举左和上方(为了避免重复,左右和上下两者中各选一个即可)。

如果当前位置为 ‘X’,判断当前位置的左方和上方,如果两者之一出现过 ‘X’,说明在之前已经统计过该battleship了,他们属于一个ships。我们只统计每个ships中的第一个battleship,其余的battleship就跳过,避免重复

时间复杂度O(m * n)

C ++ 代码如下:

class Solution {
public:
    int countBattleships(vector<vector<char>>& board) {
        //题目可能有歧义
        //按照英文翻译,紧挨着的战舰battleship应该算作一个ships,统计ships的数量
        //遍历board遇到battleship就把与它在一个ships的battleship全变为'.',更新答案
        //时间复杂度O(m * n * max(m,n))

        //方法二O(m * n) 且不改变board的值
        //枚举起点,只在X刚出现的位置统计个数,枚举左和上方
        int ans = 0;
        int m = board.size();
        int n = board[0].size();
        for(int i = 0; i < m; i ++) {
            for(int j = 0 ; j < n ; j ++) {
                if(board[i][j] == 'X') {
                    if(i > 0 && board[i - 1][j] == 'X') continue; //上
                    if(j > 0 && board[i][j - 1] == 'X') continue; //左
                    ans ++;
                }
            }
        }

        return ans;


        //方法一
        // int ans = 0;
        // int m = board.size();
        // int n = board[0].size();
        // for(int i = 0 ; i < m; i ++) {
        //     for(int j = 0; j < n; j ++) {
        //         if(board[i][j] == 'X') {
        //             ans ++;
        //             board[i][j] = '.';
        //             for(int k = i + 1; k < m && board[k][j] == 'X'; k ++) {
        //                 board[k][j] = '.';
        //             }

        //             for(int k = j + 1; k < n && board[i][k] == 'X'; k ++) {
        //                 board[i][k] = '.';
        //             }
        //         }
        //     }
        // }

        // return ans;
    }
};
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo夏末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值