专题4:矩阵
题目463:岛屿的周长(NO)
- 解题思路:每个方块必定有四个边,直接判断每个方块不合法的边数然后减去就行了。
给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有"湖"("湖" 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
cpp
class Solution {
public:
int islandPerimeter(vector<vector<int>>& grid) {
//直接从侧面入手,查看哪些不能作为边长,靠着方块的就不能算边长
int ans=0;
for(int i=0;i<grid.size();i++)
{
for(int j=0;j<grid[i].size();j++)
{
if(grid[i][j]==1)
{
//是岛屿,开始判断不合法的边
int count=4;//原来合法的边数
if(j>=1&&grid[i][j-1]==1)count--;//左边不合法
if(j<grid[i].size()-1&&grid[i][j+1]==1)count--;//右边不合法
if(i>=1&&grid[i-1][j]==1)count--;//上边不合法
if(i<grid.size()-1&&grid[i+1][j]==1)count--;//下边不合法
ans+=count;
}
}
}
return ans;
}
};
题目566:重塑矩阵(NO)
- 解题思路:先判断元素的个数是否不变,再使用vector构建二维数组的方法重新构建一个容器,后面通过将原来数组展开成一位数组进行for遍历,进行数据的填充。
在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。
给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 r 和 c ,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。
如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
cpp
class Solution {
public:
vector<vector<int>> matrixReshape(vector<vector<int>>& mat, int r, int c) {
int previous_row=mat.size();
int previous_col=mat[0].size();
if(previous_row*previous_col!=r*c)
{
//元素个数不一样了,表示不能重塑,返回元素组
return mat;
}
//重新构建一个r行c列的容器
vector<vector<int>> ans(r,vector<int>(c));//记住这种写法
for(int i=0;i<previous_row*previous_col;i++)
{
//这里主要是以列为主,填完一列到下一个
ans[i/c][i%c]=mat[i/previous_col][i%previous_col];
}
return ans;
}
};
题目661:图片平滑器(YES)
- 这题我自己给出的不是很好,是强行判断周边的所有元素的状态。解析给出的也是用时四层for强行分析,值得借鉴
图像平滑器 是大小为 3 x 3 的过滤器,用于对图像的每个单元格平滑处理,平滑处理后单元格的值为该单元格的平均灰度。
每个单元格的 平均灰度 定义为:该单元格自身及其周围的 8 个单元格的平均值,结果需向下取整。(即,需要计算蓝色平滑器中 9 个单元格的平均值)。
如果一个单元格周围存在单元格缺失的情况,则计算平均灰度时不考虑缺失的单元格(即,需要计算红色平滑器中 4 个单元格的平均值)。
- myself
cpp
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
//我现在没想到什么好的办法直接遍历然后逐个判断周边情况
int row=img.size();
int col=img[0].size();
vector<vector<int>>ans(row,vector<int>(col));
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
//逐个判断周边情况
int sum=0;
int count=1;//记录格子数量
//自己
sum+=img[i][j];
//判断左边是否有值
if(j>=1)
{
sum+=img[i][j-1];
count++;
}
//判断是否有右值
if(j<col-1)
{
sum+=img[i][j+1];
count++;
}
//判断是否有下值
if(i<row-1)
{
sum+=img[i+1][j];
count++;
}
//判断是否有上值
if(i>=1)
{
sum+=img[i-1][j];
count++;
}
//判断左下值
if(j>=1&&i<row-1)
{
sum+=img[i+1][j-1];
count++;
}
//判断右下值
if(j<col-1&&i<row-1)
{
sum+=img[i+1][j+1];
count++;
}
//判断左上值
if(j>=1&&i>=1)
{
sum+=img[i-1][j-1];
count++;
}
//判断右上值
if(j<col-1&&i>=1)
{
sum+=img[i-1][j+1];
count++;
}
ans[i][j]=sum/count;
}
}
return ans;
}
};
- 解析
cpp
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
int m = img.size(), n = img[0].size();
vector<vector<int>> ret(m, vector<int>(n));
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];
}
}
}
ret[i][j] = sum / num;
}
}
return ret;
}
};
题目733:图像渲染(NO)
- 广度优先遍历,每当检查一个队列里的节点时,都会检查其周边节点是否满足条件,满足就进入。
有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。
你也被给予三个整数 sr , sc 和 newColor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充 。
为了完成 上色工作 ,从初始像素开始,记录初始坐标的 上下左右四个方向上 像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应 四个方向上 像素值与初始坐标相同的相连像素点,......,重复该过程。将所有有记录的像素点的颜色值改为 newColor 。
最后返回 经过上色渲染后的图像 。
cpp
class Solution {
public:// 上 下 左 右
const int dr[4]={-1, 1, 0, 0 };
const int dc[4]={ 0, 0, -1, 1};
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
int max_row=image.size();
int max_col=image[0].size();
//使用广度优先遍历,用队列
int current_color=image[sr][sc];
if(color==current_color)
{
//如果第一个要修改的值就不满足修改条件,返回
return image;
}
queue<pair<int,int>>que;
//先将自身节点入队
//pair<int,int>p={sr,sc};
que.push(pair<int,int>(sr,sc));
//不为空则循环执行
while(!que.empty())
{
auto front=que.front();
int row=front.first;
int col=front.second;
//修改自身的值
image[row][col]=color;
//出队
que.pop();
//每个元素四个方向都要检查
for(int i=0;i<4;i++)
{
//dx和dy可以显示上下左右的值
int index_row=row+dr[i];
int index_col=col+dc[i];
//判断是否符合条件
if(index_row>=0&&index_row<max_row&&index_col>=0&&index_col<max_col
&&image[index_row][index_col]==current_color)
{
//满足条件,入队
que.push(pair<int,int>(index_row,index_col));
}
}
}
return image;
}
};
题目766:托普利兹矩阵(YES)
- 解题思路:直接两层for先遍历一遍所有元素,并再遍历的过程中检查每个元素的右下角的值是否等于当前值,如果不等,则不满足条件,直接返回即可。
给你一个 m x n 的矩阵 matrix 。如果这个矩阵是托普利茨矩阵,返回 true ;否则,返回 false 。
如果矩阵上每一条由左上到右下的对角线上的元素都相同,那么这个矩阵是 托普利茨矩阵 。
- myself
cpp
class Solution {
public:
//这里增量的设置其实是多余的,我只是想巩固一下这一专题的解题套路
const int dr=1;
const int dc=1;//定义右下角的增量
bool isToeplitzMatrix(vector<vector<int>>& matrix) {
int row=matrix.size();
int col=matrix[0].size();
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
//遍历每一个元素,并判断每个一的右下角的值是相同
//如果不同则直接返回false,如果没有,则继续判断
int current_row=i+dr;
int current_col=j+dc;
if(current_row<row&¤t_col<col&&
matrix[i][j]!=matrix[current_row][current_col])
{
//右下角不相等,返回false
return false;
}
}
}
return true;
}
};
题目832:翻转图像(YES)
- 解题思路:一次for遍历每一个容器,然后对每一个容器使用双指针进行翻转操作,翻转的同时使用^(异或)运算对值进行改变(1-0,0-1)
给定一个 n x n 的二进制矩阵 image ,先 水平 翻转图像,然后 反转 图像并返回 结果 。
水平翻转图片就是将图片的每一行都进行翻转,即逆序。
例如,水平翻转 [1,1,0] 的结果是 [0,1,1]。
反转图片的意思是图片中的 0 全部被 1 替换, 1 全部被 0 替换。
例如,反转 [0,1,1] 的结果是 [1,0,0]。
- myself
cpp
class Solution {
public:
vector<vector<int>> flipAndInvertImage(vector<vector<int>>& image) {
//这里反转的思路我打算使用双指针来操作,并在反转的过程中对值进行修改
int n=image.size();
for(int i=0;i<n;i++)
{
//对每一个容器进行双指针操作
int left=0;
int right=n-1;
while(left<=right)
{
//先修改值再交换元素,使用异或运算
if(left!=right)
{
image[i][left] ^=1;
image[i][right]^=1;
}else
{
image[i][left]^=1;
}
//交换两个元素
swap(image[i][left],image[i][right]);
left++;
right--;
}
}
return image;
}
};
专题5:枚举
题目1534:统计好三元组(NO)
- 解题思路:这题直接三层for就可以直接暴力解决了,当时让我感到疑惑的一个点是三层for为什么就可以遍历完所有的三元组了。
给你一个整数数组 arr ,以及 a、b 、c 三个整数。请你统计其中好三元组的数量。
如果三元组 (arr[i], arr[j], arr[k]) 满足下列全部条件,则认为它是一个 好三元组 。
0 <= i < j < k < arr.length
|arr[i] - arr[j]| <= a
|arr[j] - arr[k]| <= b
|arr[i] - arr[k]| <= c
其中 |x| 表示 x 的绝对值。
返回 好三元组的数量 。
cpp
class Solution {
public:
int countGoodTriplets(vector<int>& arr, int a, int b, int c) {
//直接暴力三层for
int ans=0;
for(int i=0;i<arr.size();i++)
{
for(int j=i+1;j<arr.size();j++)
{
for(int k=j+1;k<arr.size();k++)
{
//判断是否满是条件
if(abs(arr[i]-arr[j])<=a&&abs(arr[j]-arr[k])<=b
&&abs(arr[i]-arr[k])<=c)
{
ans++;
}
}
}
}
return ans;
}
};
题目1566:重复至少k次且长度为M的模式(NO)
- 解题思路:直接暴力的思路,遍历所有的模式,并且存储当前的模式,与后面连续的模式进行比较,看是否满足条件
给你一个正整数数组 arr,请你找出一个长度为 m 且在数组中至少重复 k 次的模式。
模式 是由一个或多个值组成的子数组(连续的子序列),连续 重复多次但 不重叠 。 模式由其长度和重复次数定义。
如果数组中存在至少重复 k 次且长度为 m 的模式,则返回 true ,否则返回 false 。
cpp
class Solution {
public:
bool containsPattern(vector<int>& arr, int m, int k) {
int len = arr.size();
//如果输入长度连一次模式匹配的长度都没有,必然是错误的
if (len < m)
{
return false;
}
//遍历每一个模式
for (int i = 0; i <= len - m; i++)
{
vector<int> pattern(m);//存储当前的模式
for (int j = 0; j < m; j++)
{
pattern[j] = arr[i + j];
}
int count = 1;//自己的模式算一个
for (int p = i + m; p <= len - m; p += m)
{//从下一个模式开始匹配
bool matched = true;
for (int q = 0; q < m; q++)
{
//逐一比较里面的元素
if (arr[p + q] != pattern[q])
{
matched = false;
break;
}
}
if (matched)
{
count++;
if (count == k)
{
return true;
}
} else
{
//这里要求要连续,不连续则匹配下一个
break;
}
}
}
return false;
}
};