如何在C#中不借助额外数组原地转换二维数组?
原地实现二维数组循环右下移一位的方案
方案一:分两步实现(每行右移+每列下移)
这种方法逻辑直观,空间复杂度仅为O(1)(仅使用几个临时变量),时间复杂度O(rows*cols),和原代码效率完全一致。
核心思路:每个元素最终要移动到((i+1)%rows, (j+1)%cols),等价于先将每行元素循环右移一位,再将每列元素循环下移一位(顺序调换为“先下移再右移”,结果完全相同)。
实现代码
public static void TransformArrayInPlace(int[,] matrix) { int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); // 第一步:每行循环右移一位 for (int i = 0; i < rows; i++) { int temp = matrix[i, cols - 1]; for (int j = cols - 1; j > 0; j--) { matrix[i, j] = matrix[i, j - 1]; } matrix[i, 0] = temp; } // 第二步:每列循环下移一位 for (int j = 0; j < cols; j++) { int temp = matrix[rows - 1, j]; for (int i = rows - 1; i > 0; i--) { matrix[i, j] = matrix[i - 1, j]; } matrix[0, j] = temp; } } public static void Main(string[] args) { int[,] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; TransformArrayInPlace(matrix); // 输出转换后的数组 for (int i = 0; i < matrix.GetLength(0); i++) { for (int j = 0; j < matrix.GetLength(1); j++) { Console.Write(matrix[i, j] + " "); } Console.WriteLine(); } }
效果验证
原数组:
1 2 3 4 5 6 7 8 9
每行右移后:
3 1 2 6 4 5 9 7 8
每列下移后:
9 7 8 3 1 2 6 4 5
与原代码使用临时数组的输出完全一致。
方案二:循环链替换法(严格O(1)空间)
如果需要完全避免任何额外数组(包括标记访问状态的数组),可以采用循环链替换思路:每个元素的移动路径会形成闭合循环链,仅用一个临时变量保存当前值,即可完成链内元素的依次替换。
实现代码
public static void TransformArrayInPlace(int[,] matrix) { int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); int chainCount = Gcd(rows, cols); for (int k = 0; k < chainCount; k++) { int currentI = k / cols; int currentJ = k % cols; int temp = matrix[currentI, currentJ]; while (true) { int nextI = (currentI + 1) % rows; int nextJ = (currentJ + 1) % cols; if (nextI == k / cols && nextJ == k % cols) break; int nextTemp = matrix[nextI, nextJ]; matrix[nextI, nextJ] = temp; temp = nextTemp; currentI = nextI; currentJ = nextJ; } matrix[k / cols, k % cols] = temp; } } // 辅助方法:计算最大公约数 private static int Gcd(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; }
思路说明
以3x3数组为例,存在3个独立循环链:
- (0,0) → (1,1) → (2,2) → (0,0)
- (0,1) → (1,2) → (2,0) → (0,1)
- (0,2) → (1,0) → (2,1) → (0,2)
遍历每个循环链的起点,依次将链内元素替换到目标位置,全程仅用一个临时变量保存被覆盖的值,无额外内存开销。
优化建议
- 小规模数组优先选方案一,代码更易读、易维护。
- 超大数组且对内存占用要求极高时,选方案二,完全无额外数组开销。
- 两种方案时间复杂度均为O(rows*cols),与原代码效率一致,无性能损失。
内容的提问来源于stack exchange,提问作者satanmoo
相关产品推荐
相关产品推荐

