LeetCode刷题day21

简介: LeetCode刷题day21

今日刷题重点----螺旋矩阵

59. 螺旋矩阵 II

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:

ff0d57ee819f428d88a901234db1e3f6.png

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]


思路1:

根据卡尔大佬的说法,求解本题依然是要坚持循环不变量原则。


模拟顺时针画矩阵的过程:


填充上行从左到右

填充右列从上到下

填充下行从右到左

填充左列从下到上

由外向内一圈一圈这么画下去。


可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人。


这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开又闭的原则,这样这一圈才能按照统一的规则画下来。


那么我按照左闭右开的原则,来画一圈,大家看一下


3ee04e32a97a422eb3dc23e749b0535f.png

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。


这也是坚持了每条边左闭右开的原则。


一些同学做这道题目之所以一直写不好,代码越写越乱。


就是因为在画每一条边的时候,一会左开又闭,一会左闭右闭,一会又来左闭右开,岂能不乱。


参考代码1

//1.一圈一圈的进行填数.圈数=n/2,如果n为奇数,则中间的那个数单独处理.
//2.每次圈的边长相比上一次总是少二 ,以n=6为例:6 4 2  所以可以使用一个变量每次循环之后加2
//3.在进行循环时,要按照一定的规则,既要让所有的点都被遍历到也尽量不要多次进行遍历. 我们采用左闭右开的规则
vector<vector<int>> generateMatrix(int n) {
  vector<vector<int>> res(n,vector<int>(n,0));//定义一个二维数组
  int loop = n / 2;
  int cnt = 1;//填充变量
  int offset = 1;
  int startX = 0,startY = 0;//定义每圈的起始坐标
  while(loop--) {
    int i = startX;
    int j = startY;
    //从左到右
    for(; j< startY+n-offset; j++) {
      res[i][j] = cnt++;
    }
    //从上到下
    for(; i<startX+n-offset; i++) {
      res[i][j]=cnt++;
    }
    //从右向左
    for(; j>startY; j--) {
      res[i][j] = cnt++;
    }
    //从下到上
    for(; i>startX; i--) {
      res[i][j] = cnt++;
    }
    //offset变量加2
    offset+=2;
    //startX,startY进行更新
    startX++;
    startY++;
  }
  if(n%2) { //如果n是奇数.
    res[n/2][n/2] = cnt;
  }
  return res;
}

思路2

生成一个 n×n 空矩阵 res,随后模拟整个向内环绕的填入过程:


定义当前左右上下边界 l,r,u,d,初始值 num = 1,迭代终止值 sum= n * n;


当 num <= sum 时,始终按照 从左到右 从上到下 从右到左 从下到上 填入顺序循环,每次填入后:num++,得到下一个需要填入的数字;


更新边界:例如从左到右填完后,上边界 u++,相当于上边界向内缩 1。


使用num <= sum而不是l < r || u < d作为迭代条件,是为了解决当n为奇数时,矩阵中心数字无法在迭代过程中被填充的问题。


最终返回 res即可


参考代码2

vector<vector<int>> generateMatrix(int n) {
  vector<vector<int>> res(n,vector<int>(n,0));
  int l = 0,r =n-1,u = 0,d = n-1;
  int sum = n*n,num=1;
  //cout<<"123"<<endl;
  while(num<=sum) {
    //从左到右
    for(int i = l; i<=r; i++) {
      res[u][i]=num++;
    }
    u++;
    //从上到下
    for(int i = u; i<=d; i++) {
      res[i][r] = num++;
    }
    r--;
    //从右向左
    for(int i = r; i>=l; i--) {
      res[d][i]=num++;
    }
    d--;
    //从下到上
    for(int i = d; i>=u; i--) {
      res[i][l] = num++;
    }
    l++;
    cout<<num<<endl;
  }
  return res;
}

54. 螺旋矩阵

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

示例 1:

fe32a8e018c54ad0b9b6b31782714dc3.png

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

447ab73869024341927b4b9e4014be5b.png

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

思路分析

和上面的题思路二很相似,但本题不同的是会出现矩形;,所以中间的for循环也要对sum进行限制,防止减成0后,后面的for还执行.

参考代码

//思路:参考螺旋矩阵二  注意每层for循环中间的sum条件也要限制. 具体原因可以举个例子比如说只有一行的话,
//从左到右循环完毕按说已经结束了,但是 从右向左的for依旧会被执行.. 
vector<int> spiralOrder(vector<vector<int>>& matrix) {
  vector<int> res;
  if(matrix.size()==0){
    return res;
  }
  int n = matrix.size();
  int m = matrix[0].size(); 
  int l = 0,r = m-1,u = 0,d = n-1;
  int sum = n*m;
  while(sum){
    //从左到右
    for(int i=l;i<=r&&sum;i++){
      res.push_back(matrix[u][i]);
      sum--;
    } 
    u++;//上边界++ 
    //从上到下 
    for(int i = u;i<=d&&sum;i++){
      res.push_back(matrix[i][r]);
      sum--;
    }
    r--;//右边界
    //从右 向左
    for(int i = r;i>=l&&sum;i--){
      res.push_back(matrix[d][i]);
      sum--;
    } 
    d--;
    //从下到上
    for(int i = d;i>=u&&sum;i--){
      res.push_back(matrix[i][l]);
      sum--;
    } 
    l++;//左边界. 
  }
  return res;
}

剑指 Offer 29. 顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

思路分析:

和上面的题类似

参考代码

vector<int> spiralOrder(vector<vector<int>>& matrix) {
  if(matrix.size()==0){
    return {};
  }
  int n = matrix.size();
  int m = matrix[0].size();
  int l = 0,r = m-1,u = 0,d = n-1;
  int sum = n*m,num=1;
  vector<int> ans;
  while(num<=sum){
    //从左到右
    for(int i =l;i<=r;i++){
      V.push_back(matrix[u][i]);
      num++;
    } 
    u++;
    //从上到下
    for(int i = u;i<=d;i++){
      V.push_back(matrix[i][r]);
      num++; 
    }
    r--;
    //从右到左
    for(int i=r;i>=l;i--){
      V.push_back(matrix[d][i]);
      num++;
    }
    d--;
    //从下到上 
    for(int i = d;i>=u;i--){
      V.push_back(matrix[i][l]);
      num++;
    }
    l++;
  } 
  return V;
}
相关文章
|
28天前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
2月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
50 6
|
2月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
43 4
|
2月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
99 2
|
28天前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
2月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
47 7
|
2月前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
22 4
|
2月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
48 5
|
2月前
|
算法 Python
【Leetcode刷题Python】 LeetCode 2038. 如果相邻两个颜色均相同则删除当前颜色
本文介绍了LeetCode 2038题的解法,题目要求在一个由'A'和'B'组成的字符串中,按照特定规则轮流删除颜色片段,判断Alice是否能够获胜,并提供了Python的实现代码。
45 3
|
2月前
|
算法 Python
【Leetcode刷题Python】剑指 Offer 33. 二叉搜索树的后序遍历序列
本文提供了一种Python算法,用以判断给定整数数组是否为某二叉搜索树的后序遍历结果,通过识别根节点并递归验证左右子树的值是否满足二叉搜索树的性质。
21 3