1. 矩阵旋转

将 n × n 矩阵顺时针旋转 90°。

我的思路是 “ 从外到内一层一层旋转 ”。

一个 n × n 矩阵有 (n + 1) / 2 层,每层有 4 部分,将这 4 部分旋转。

顺时针旋转 90° 就是将 matrix[n - 1 - q][p] 赋值给 matrix[p][q] 即可。

C++代码:

 void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = ; i < (n + ) / ; i++) {
for (int j = i; j < n - - i; j++) {
int p = i, q = j;
int temp = matrix[p][q];
for (int k = ; k < ; k++) {
matrix[p][q] = matrix[n - - q][p];
int tp = p;
p = n - - q;
q = tp;
}
matrix[p][q] = temp;
}
}
}

答案的方法非常直观易懂!学到了!

首先将矩阵从上到下逆置,然后按对角线对称交换元素。

1 2 3    7 8 9    7 4 1
4 5 6 => 4 5 6 => 8 5 2
7 8 9 1 2 3 9 6 3
 void rotate(vector<vector<int> > &matrix) {
reverse(matrix.begin(), matrix.end());
for (int i = ; i < matrix.size(); ++i) {
for (int j = i + ; j < matrix[i].size(); ++j)
swap(matrix[i][j], matrix[j][i]);
}
}

逆时针旋转的原理类似。

首先将矩阵从左到右逆置,然后按对角线对称交换元素。注意从上到下和从左到右逆置矩阵的区别!

1 2 3     3 2 1     3 6 9
4 5 6 => 6 5 4 => 2 5 8
7 8 9 9 8 7 1 4 7
 void anti_rotate(vector<vector<int> > &matrix) {
for (auto vi : matrix)
reverse(vi.begin(), vi.end());
for (int i = ; i < matrix.size(); ++i) {
for (int j = i + ; j < matrix[i].size(); ++j)
swap(matrix[i][j], matrix[j][i]);
}
}

2. 矩阵螺旋遍历

给定 m x n 矩阵,以螺旋顺序遍历矩阵所有元素。

e.g. 给出如下矩阵

[
    [ 1, 2, 3 ],
    [ 4, 5, 6 ],
    [ 7, 8, 9 ]
]

返回 [1, 2, 3, 6, 9, 8, 7, 4, 5]。

我尝试定义行标记 i 和列标记 j,第一层是 (0, 0),第二层是 (1, 1),不断循环。每次循环内改变 i 和 j,实现螺旋遍历。但实现起来代码要写的非常冗长,比如最内层只有一行或只有一列时,就会出错。于是看了别人的解法,深受启发!

方法一:死办法

 vector<int> spiralOrder(vector<vector<int>>& matrix) {
if (matrix.empty()) return {};
int m = matrix.size(), n = matrix[].size();
vector<int> result(m * n);
int u = , d = m - , l = , r = n - , k = ;
while () {
for (int j = l; j <= r; j++) result[k++] = matrix[u][j];
if (++u > d) break;
for (int i = u; i <= d; i++) result[k++] = matrix[i][r];
if (--r < l) break;
for (int j = r; j >= l; j--) result[k++] = matrix[d][j];
if (--d < u) break;
for (int i = d; i >= u; i--) result[k++] = matrix[i][l];
if (++l > r) break;
}
return result;
}

定义 u(上),d(下),l(左),r(右)表示各个方向的极限下标,转了一圈后,由于 ++u、--r、--d、++l ,进入里面一层继续螺旋遍历。

此外,由于知道结果数组大小(m x n),预先分配空间并直接赋值要比 push_back 效率高。

方法二:方向矩阵法

原理:

螺旋遍历就是不断地向 4 个方向(右、下、左、上)移动。假设要处理一个 5 x 3 的矩阵,初始标志位坐标设为 (0, -1),即 '0' 的位置。

0 [ 1  2  3  4  5]
[ 6 7 8 9 10]
[11 12 13 14 15]

接下来需要移动标志位:

  • 向右移动 5 位
    向下移动 2 位
  • 向左移动 4 位
    向上移动 1 位
  • 向右移动 3 位
    向下移动 0 位 --> 结束

注意到方向一直是 “ 右 → 下 → 左 →上 ”,水平移动的步数是 { 5,4,3 } (5 是矩阵的行数),竖直移动的步数是 { 2,1,0 } (2 是矩阵的列数减 1)。

因此,可以构造一个方向矩阵存储所有方向,以及一个含有两个元素的数组存储水平和竖直移动的步数。这样就用一次循环代替了四次循环。

而且这样做的一个好处是,如果我们要改变遍历的起点(如从右上角元素开始),或者改变螺旋的方向(如逆时针),只需要改变方向矩阵,循环主体不需要改变。虽然更为复杂,但增加了代码的可重用性!

C++实现:

 vector<int> spiralOrder(vector<vector<int>>& matrix) {
if (matrix.empty()) return {};
int m = matrix.size(), n = matrix[].size();
vector<int> result;
vector<vector<int>> dir = {{, }, {, }, {, -}, {-, }};
vector<int> step = {n, m - };
int i = , j = -, dirIndex = , stepIndex = ;
while (step[stepIndex]) {
for (int k = ; k < step[stepIndex]; k++) {
i += dir[dirIndex][];
j += dir[dirIndex][];
result.push_back(matrix[i][j]);
}
step[stepIndex]--;
stepIndex = (stepIndex + ) % ;
dirIndex = (dirIndex + ) % ;
}
return result;
}

可以发现 stepIndex 刚好等于 dirIndex % 2,可以进行替换,少定义一个变量,但也降低了可读性。

3. 螺旋矩阵

给定一个整数 n,产生一个方阵,该方阵由元素 1 到 n2 以螺旋顺序填充。

e.g. n = 3,返回矩阵

[
    [ 1, 2, 3 ],
    [ 8, 9, 4 ],
    [ 7, 6, 5 ]
]

死办法,定义 u、d、l、r。

 vector<vector<int>> generateMatrix(int n) {
/* 注意 vector<vector<int>> 的初始化方式 */
vector<vector<int>> result(n, vector<int>(n));
int u = , r = n - , d = n - , l = , k = ;
while() {
for (int j = l; j <= r; j++) result[u][j] = k++;
if (++u > d) break;
for (int i = u; i <= d; i++) result[i][r] = k++;
if (--r < l) break;
for (int j = r; j >= l; j--) result[d][j] = k++;
if (--d < u) break;
for (int i = d; i >= u; i--) result[i][l] = k++;
if (++l > r) break;
}
return result;
}

也可以使用定义方向矩阵的方法。

【LeetCode】矩阵操作的更多相关文章

  1. Leetcode 566. Reshape the Matrix 矩阵变形(数组,模拟,矩阵操作)

    Leetcode 566. Reshape the Matrix 矩阵变形(数组,模拟,矩阵操作) 题目描述 在MATLAB中,reshape是一个非常有用的函数,它可以将矩阵变为另一种形状且保持数据 ...

  2. Linear regression with one variable算法实例讲解(绘制图像,cost_Function ,Gradient Desent, 拟合曲线, 轮廓图绘制)_矩阵操作

    %测试数据 'ex1data1.txt', 第一列为 population of City in 10,000s, 第二列为 Profit in $10,000s 1 6.1101,17.592 5. ...

  3. iOS开发UI篇—Quartz2D使用(矩阵操作)

    iOS开发UI篇—Quartz2D使用(矩阵操作) 一.关于矩阵操作 1.画一个四边形 通过设置两个端点(长和宽)来完成一个四边形的绘制. 代码: - (void)drawRect:(CGRect)r ...

  4. 【iOS】Quartz2D矩阵操作

    前面画基本图形时,画四边形是由几条直线拼接成的,现在有更简便的方法. 一.关于矩阵操作 1.画一个四边形 通过设置两个端点(长和宽)来完成一个四边形的绘制. 代码: - (void)drawRect: ...

  5. MATLAB命令大全和矩阵操作大全

    转载自: http://blog.csdn.net/dengjianqiang2011/article/details/8753807 MATLAB矩阵操作大全 一.矩阵的表示在MATLAB中创建矩阵 ...

  6. Matlab、R向量与矩阵操作 z

    已有 1849 次阅读 2012-8-2 15:15 |系统分类:科研笔记|关键词:矩阵 480 window border center Matlab.R向量与矩阵操作   描    述 Matla ...

  7. Python中的矩阵操作

    Numpy 通过观察Python的自有数据类型,我们可以发现Python原生并不提供多维数组的操作,那么为了处理矩阵,就需要使用第三方提供的相关的包. NumPy 是一个非常优秀的提供矩阵操作的包.N ...

  8. poj3735—Training little cats(特殊操作转化为矩阵操作)

    题目链接:http://poj.org/problem?id=3735 题目意思: 调教猫咪:有n只饥渴的猫咪,现有一组羞耻连续操作,由k个操作组成,全部选自: 1. g i 给第i只猫咪一颗花生 2 ...

  9. Matlab、R向量与矩阵操作

    Matlab.R向量与矩阵操作   描    述 Matlab R 1 建立行向量v=[1 2  3 4] v=[1 2 3 4] v<-c(1,2,3,4)或v<-scan(),然后输入 ...

  10. MATLAB矩阵操作大全

    转载自:http://blog.csdn.net/dengjianqiang2011/article/details/8753807 MATLAB矩阵操作大全 一.矩阵的表示 在MATLAB中创建矩阵 ...

随机推荐

  1. 【译】第9节---EF Code First中数据注解

    原文:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF Code-First ...

  2. Linux命令去重统计排序

    利用Linux命令进行文本按行去重并按重复次数排序   linux命令行提供了非常强大的文本处理功能,组合利用linux命令能实现好多强大的功能.本文这里举例说明如何利用Linux命令行进行文本按行去 ...

  3. Java基础 --Unix与Mac系统 文件路径分隔符(一)

    斜杠‘/’与反斜杠‘\’在不同系统的使用 1)Window平台使用反斜杠'\'作为文件层级分隔符:Windows使用反斜杠作为DOS命令提示符的参数标志,随着发展DOS命令符逐渐被淘汰,大部分情况下斜 ...

  4. 【BZOJ】3209: 花神的数论题

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3209 显然是按照二进制位进行DP. 考虑预处理$F[i][j]$表示到了二进制的第$i$位 ...

  5. pymongo.errors.OperationFailure: Authentication failed.

    mongoDB有不同的认证机制,3.0版本以后采用的是'MONGODB-CR', 之前的版本采用的是'MONGODB-CR'. 所以,以我的版本情况,显然应该用'SCRAM-SHA-1' from p ...

  6. 3. 使用vue-cli创建项目

    eslint: 用来做项目编码规范检查的工具基本原理: 定义了很多规则, 检查项目的代码一旦发现违背了某个规则就输出相应的提示信息有相应的配置, 可定制检查 1. 创建项目 vue脚手架(vue-cl ...

  7. PostegreSQL模板数据库

    模板数据库 模板数据库就是创建新database时,PostgreSQL会基于模板数据库制作一份副本,其中会包含所有的数据库设置和数据文件. CREATE DATABASE 实际上是通过拷贝一个现有的 ...

  8. Meta referrer标签的,可以防止CSRF的攻击

    Meta referrer标签的简要介绍 在某些情况下,出于一些原因,网站想要控制页面发送给 server 的 referer 信息的情况下,可以使用这一 referer metadata 参数. 参 ...

  9. Qt5鼠标事件及实例

    mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QLa ...

  10. Codeforces 920G - List Of Integers

    920G - List Of Integers 思路:容斥+二分 代码: #include<bits/stdc++.h> using namespace std; #define ll l ...