leetcode
leetcode 2501 ~ 2550
循环移位后的矩阵相似检查

循环移位后的矩阵相似检查

难度:

标签:

题目描述

You are given a 0-indexed m x n integer matrix mat and an integer k. You have to cyclically right shift odd indexed rows k times and cyclically left shift even indexed rows k times.

Return true if the initial and final matrix are exactly the same and false otherwise.

 

Example 1:

Input: mat = [[1,2,1,2],[5,5,5,5],[6,3,6,3]], k = 2
Output: true
Explanation:


Initially, the matrix looks like the first figure. 
Second figure represents the state of the matrix after one right and left cyclic shifts to even and odd indexed rows.
Third figure is the final state of the matrix after two cyclic shifts which is similar to the initial matrix.
Therefore, return true.

Example 2:

Input: mat = [[2,2],[2,2]], k = 3
Output: true
Explanation: As all the values are equal in the matrix, even after performing cyclic shifts the matrix will remain the same. Therefeore, we return true.

Example 3:

Input: mat = [[1,2]], k = 1
Output: false
Explanation: After one cyclic shift, mat = [[2,1]] which is not equal to the initial matrix. Therefore we return false.

 

Constraints:

  • 1 <= mat.length <= 25
  • 1 <= mat[i].length <= 25
  • 1 <= mat[i][j] <= 25
  • 1 <= k <= 50

代码结果

运行时间: 26 ms, 内存: 16.1 MB


/*
 * 题目思路:
 * 1. 使用Java Stream API来处理矩阵的行移动。
 * 2. 对于奇数行,向右循环移动k次;对于偶数行,向左循环移动k次。
 * 3. 移动后的矩阵如果和原矩阵相等,则返回true,否则返回false。
 */
import java.util.Arrays;
import java.util.stream.IntStream;

public class SolutionStream {
    public boolean isSameMatrix(int[][] mat, int k) {
        int m = mat.length;
        int n = mat[0].length;
        int[][] transformedMat = new int[m][n];
        
        // 遍历每一行并进行移动
        IntStream.range(0, m).forEach(i -> {
            int move = k % n;
            if (i % 2 == 0) { // 偶数行向左移
                IntStream.range(0, n).forEach(j -> {
                    transformedMat[i][(j - move + n) % n] = mat[i][j];
                });
            } else { // 奇数行向右移
                IntStream.range(0, n).forEach(j -> {
                    transformedMat[i][(j + move) % n] = mat[i][j];
                });
            }
        });
        
        // 检查变换后的矩阵是否与原矩阵相同
        return IntStream.range(0, m).allMatch(i -> 
            IntStream.range(0, n).allMatch(j -> transformedMat[i][j] == mat[i][j])
        );
    }
}

解释

方法:

题解的核心思路是首先对矩阵中的奇数行和偶数行分别进行右移和左移操作,然后比较操作后的矩阵和原始矩阵是否完全相同。首先定义一个旋转行的函数,根据行移动的方向(左或右)和移动的次数来计算新的行顺序。循环遍历矩阵中的每一行,根据行的索引是奇数还是偶数,使用旋转函数进行相应的行移动。最后,将旋转后的矩阵和原始矩阵进行比较,如果两者相等,则返回 true,否则返回 false。

时间复杂度:

O(m * n)

空间复杂度:

O(m * n)

代码细节讲解

🦆
为什么选择对偶数行进行左移而对奇数行进行右移?是否有特定的原因或是这样的操作对于题目的解决有何帮助?
在题目中,选择对偶数行左移和奇数行右移是基于对称性的考虑,这样的操作可以帮助我们在实现时通过统一的处理逻辑来简化编码和调试。实际上,题目的要求是可以自由设定的,左移和右移只是为了达到题目要求的循环移位效果。这种分别处理偶数行和奇数行的方法,可以让我们更加清晰地观察到每一行的变化,同时也是一种有效的避免错误和确认变化是否正确的手段。
🦆
在`rotate_row`函数中,对于移动次数大于行长度的情况,为什么采用取模操作来减少不必要的循环?这样做有什么优势?
在`rotate_row`函数中使用取模操作是为了处理移动次数大于行长度的情况,避免进行无效的全圈循环,从而提高效率。取模操作确保移动次数被简化为一个周期以内的移动,即使移动次数是行长度的整数倍或更多,实际效果相当于没有移动。这样不仅减少了计算和移动的开销,而且代码更加简洁高效。例如,如果一行有5个元素,移动10次和不移动是等效的,通过取模操作可以直接得出这一结果,避免无意义的计算和处理。
🦆
既然已经创建了原始矩阵的深拷贝,为什么还需要对原始矩阵进行行的旋转而不是直接在副本上操作后与原矩阵比较?
在本题解中,我们创建了原始矩阵的深拷贝主要是为了保留一个未修改的版本,以便与修改后的矩阵进行比较,验证是否相同。深拷贝的原始矩阵作为一个不变的参照物,确保我们有一个准确无误的比较基准。对原始矩阵进行操作而不是副本,是为了避免额外的内存使用和可能的性能开销。此外,直接在原矩阵上操作可以减少数据复制的次数,从而在保持代码逻辑清晰的同时也优化性能。

相关问题