766托普利茨矩阵(数组、矩阵、小内存大数据)
给你一个 m x n 的矩阵 matrix 。如果这个矩阵是托普利茨矩阵,返回 true ;否则,返回 false 。
如果矩阵上每一条由左上到右下的对角线上的元素都相同,那么这个矩阵是 托普利茨矩阵 。
示例 1:
输入:matrix = [[1,2,3,4],[5,1,2,3],[9,5,1,2]]
输出:true
解释:
在上述矩阵中, 其对角线为:
“[9]”, “[5, 5]”, “[1, 1, 1]”, “[2, 2, 2]”, “[3, 3]”, “[4]”。
各条对角线上的所有元素均相同, 因此答案是 True 。
示例 2:
输入:matrix = [[1,2],[2,2]]
输出:false
解释:
对角线 “[1, 2]” 上的元素不同。
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 20
0 <= matrix[i][j] <= 99
进阶:
如果矩阵存储在磁盘上,并且内存有限,以至于一次最多只能将矩阵的一行加载到内存中,该怎么办? 如果矩阵太大,以至于一次只能将不完整的一行加载到内存中,该怎么办?
Related Topics 数组
思路1:将第一行与第一列的元素进行遍历,设x,y,满足 0<=x<matrix.length -1,0<=y<matrix[0].length-1,且matrix[x][y]==matrix[x+1][y+1];
class Solution {
public boolean isToeplitzMatrix(int[][] matrix) {
for (int x = 0; x < matrix.length - 1; x++) {
for (int y = 0; y < matrix[0].length - 1; y++) {
if (matrix[x][y] != matrix[x + 1][y + 1]) {
return false;
}
}
}
return true;
}
}
考虑到进阶的问题一:一次最多只能将矩阵的一行加载到内存中,我们将每一行复制到一个连续数组中,随后在读取下一行时,就与内存中此前保存的数组进行比较。
以下的实现还有点偏差,内存中必须存储两行元素
class Solution {
public boolean isToeplitzMatrix(int[][] matrix) {
// 从内存中加载一行
int[] row = matrix[0];
// 对列数进行循环
for (int r = 1; r < matrix.length; r++) {
for (int c = 1; c < matrix[0].length; c++) {
// 读取的下一行一个元素需要与前一行的前一个元素相同
if(matrix[r][c] != row[c-1]) {
return false;
}
}
//如果相同,赋值给内存中的唯一一行元素
row = matrix[r];
}
return true;
}
}
对于进阶问题二,一次只能将不完整的一行加载到内存中,我们将整个矩阵竖直切分成若干子矩阵,并保证两个相邻的矩阵至少有一列或一行是重合的,然后判断每个子矩阵是否符合要求。
还是以分治的思想
566. 重塑矩阵 [二维数组与一维数组转换]
在MATLAB中,有一个非常有用的函数 reshape,它可以将一个矩阵重塑为另一个大小不同的新矩阵,但保留其原始数据。
给出一个由二维数组表示的矩阵,以及两个正整数r和c,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的行遍历顺序填充。
如果具有给定参数的reshape操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
示例 1:
输入:
nums =
[[1,2],
[3,4]]
r = 1, c = 4
输出:
[[1,2,3,4]]
解释:
行遍历nums的结果是 [1,2,3,4]。新的矩阵是 1 * 4 矩阵, 用之前的元素值一行一行填充新矩阵。
示例 2:
输入:
nums =
[[1,2],
[3,4]]
r = 2, c = 4
输出:
[[1,2],
[3,4]]
解释:
没有办法将 2 * 2 矩阵转化为 2 * 4 矩阵。 所以输出原矩阵。
注意:
给定矩阵的宽和高范围在 [1, 100]。
给定的 r 和 c 都是正数。
Related Topics 数组
思路1:直接迁移的方法,申请一个ans[r][c]的矩阵,将nums中的元素放入ans数组中,时间复杂度O(r*c)
class Solution {
public int[][] matrixReshape(int[][] nums, int r, int c) {
// 边界判断
if (r * c != nums[0].length * nums.length) {
return nums;
}
int ans[][] = new int[r][c];
int cNums = nums[0].length;
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums[0].length; j++) {
// 将原矩阵的元素 映射到新矩阵上
ans[(i * cNums + j) / c][(i * cNums + j) % c] = nums[i][j];
}
}
return ans;
}
}
原来以为通关了,直到我看到了这个答案:
其实两者的思想是一致的,都是利用了一维数据上的元素位置 与二维数组上元素位置的映射关系,但代码更易阅读
matrix[x/c][x%c] = nums[x];
其中c就是二维数组的列数,x为一维数组中的索引位置
class Solution {
public int[][] matrixReshape(int[][] nums, int r, int c) {
// 边界判断
if (r * c != nums[0].length * nums.length) {
return nums;
}
int ans[][] = new int[r][c];
int rNums = nums.length;
int cNums = nums[0].length;
// 这里直接采用一维数组的思想,将一维数组作为转换的中介,代码更易阅读
for (int i = 0; i < rNums * cNums; i++) {
ans[i / c][i % c] = nums[i / cNums][i % cNums];
}
return ans;
}
}
二分查找(74. 搜索二维矩阵)
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true
示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-10^4 <= matrix[i][j], target <= 10^4
思路
首先每行的数据从左到右依次增大,下面行的数据都比上面行的数据大。比起“杨氏矩阵”简单了一些。其中一种思路就是可以将二维矩阵转换为一维数组,然后根据一维数据的位置计算二维数组的位置。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
// 获取矩阵的行数和列数
int m = matrix.length;
int n = matrix[0].length;
// 边界值考虑
if (target < matrix[0][0] || target > matrix[m - 1][n - 1]) {
return false;
}
// 二分查找
int left = 0, right = m * n - 1, mid;
while (left <= right) {
mid = (left+right) >> 1 ;
// 根据一维数组映射二维数组,mid/n就是这个数所在的行,mid % n就是这个数所在的列
int midVal= matrix[mid / n][mid % n];
if (target == midVal) {
return true;
} else if (target < midVal) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return false;
}
}
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.2 MB, 在所有 Java 提交中击败了11.09%的用户