Basic operations
The basic matrix operations: traversing by rows and columns, transposing, reflecting, rotating by 90 degrees in place, addition and the standard matrix multiplication, each with its cost.
Learning goals
- Traverse a matrix in row and column order
- Transpose, reflect and rotate a square matrix in place
- Add and multiply matrices and state the costs
Prerequisites
Traverse rows and columns
Row-by-row traversal runs the column index in the inner loop; column-by-column swaps the loops. Both visit all R × C cells in O(R·C) time, but row order is faster on large matrices because it reads memory sequentially. Choose the order the problem needs, and prefer row order when both are possible.
Compare the two orders in the animation.
1for (int r = 0; r < R; r++) for (int c = 0; c < C; c++) visit(g[r][c]); // row by row2for (int c = 0; c < C; c++) for (int r = 0; r < R; r++) visit(g[r][c]); // column by column
Matrix traversal orders
Interactive · edit the inputgrid · 3 × 4
visit order
Spiral: walk the outer ring clockwise, then repeat on the shrinking inner matrix.
1// row-major: consecutive memory, cache friendly2for (int r = 0; r < R; r++) for (int c = 0; c < C; c++) visit(g[r][c]);3// column-major: jumps a whole row each step4for (int c = 0; c < C; c++) for (int r = 0; r < R; r++) visit(g[r][c]);5// snake: odd rows run right to left6for (int r = 0; r < R; r++) for (int k = 0; k < C; k++) visit(g[r][r % 2 == 0 ? k : C - 1 - k]);7// spiral: peel the outer ring, then shrink the bounds8int top = 0, bottom = R - 1, left = 0, right = C - 1;9while (top <= bottom && left <= right) {10for (int c = left; c <= right; c++) visit(g[top][c]); // top side11for (int r = top + 1; r <= bottom; r++) visit(g[r][right]); // right side12if (top < bottom) for (int c = right - 1; c >= left; c--) visit(g[bottom][c]); // bottom side13if (left < right) for (int r = bottom - 1; r > top; r--) visit(g[r][left]); // left side14top++; bottom--; left++; right--; // boundary-only stops after one ring15}16// cells with the same r + c form an anti-diagonal; zigzag reverses every other one17for (int d = 0; d < R + C - 1; d++) {18for (int r = Math.max(0, d - C + 1); r <= Math.min(d, R - 1); r++) visit(g[r][d - r]);19}
Live state
R
3
C
4
Execution trace (dry run table)Show 14 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L10 | R=3 C=4 | Spiral: walk the outer ring clockwise, then repeat on the shrinking inner matrix. |
| 2 | L10 | step=1 r=0 c=0 g[r][c]=1 | Visit g[0][0] = 1 (cell 1 of 12). |
| 3 | L10 | step=2 r=0 c=1 g[r][c]=2 | Visit g[0][1] = 2 (cell 2 of 12). |
| 4 | L10 | step=3 r=0 c=2 g[r][c]=3 | Visit g[0][2] = 3 (cell 3 of 12). |
| 5 | L10 | step=4 r=0 c=3 g[r][c]=4 | Visit g[0][3] = 4 (cell 4 of 12). |
| 6 | L10 | step=5 r=1 c=3 g[r][c]=8 | Visit g[1][3] = 8 (cell 5 of 12). |
| 7 | L10 | step=6 r=2 c=3 g[r][c]=12 | Visit g[2][3] = 12 (cell 6 of 12). |
| 8 | L10 | step=7 r=2 c=2 g[r][c]=11 | Visit g[2][2] = 11 (cell 7 of 12). |
| 9 | L10 | step=8 r=2 c=1 g[r][c]=10 | Visit g[2][1] = 10 (cell 8 of 12). |
| 10 | L10 | step=9 r=2 c=0 g[r][c]=9 | Visit g[2][0] = 9 (cell 9 of 12). |
| 11 | L10 | step=10 r=1 c=0 g[r][c]=5 | Visit g[1][0] = 5 (cell 10 of 12). |
| 12 | L10 | step=11 r=1 c=1 g[r][c]=6 | Visit g[1][1] = 6 (cell 11 of 12). |
| 13 | L10 | step=12 r=1 c=2 g[r][c]=7 | Visit g[1][2] = 7 (cell 12 of 12). |
| 14 | L10 | return=[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7] | 12 cells visited: [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]. O(R x C) time. |
Transpose
The transpose swaps rows and columns: t[c][r] = g[r][c]. For a square matrix it can be done in place by swapping each pair of mirror cells across the main diagonal, visiting only the cells above the diagonal (c > r) so no pair is swapped twice. A non-square matrix needs a new array of shape C × R.
Choose Transpose and watch the mirror pairs swap.
1static void transpose(int[][] g) { // square n x n2for (int r = 0; r < g.length; r++)3for (int c = r + 1; c < g.length; c++) {4int t = g[r][c]; g[r][c] = g[c][r]; g[c][r] = t;5}6}
Transpose, reflect and rotate a matrix in place
Interactive · edit the inputgrid · 3 × 3
A 90-degree clockwise rotation is a transpose followed by a left-right reflection of every row.
1static void transpose(int[][] g) { // square matrix2for (int r = 0; r < g.length; r++)3for (int c = r + 1; c < g.length; c++) swap(g, r, c, c, r); // only above the diagonal4}5static void reflectLeftRight(int[][] g) {6for (int[] row : g) for (int lo = 0, hi = row.length - 1; lo < hi; lo++, hi--) { int t = row[lo]; row[lo] = row[hi]; row[hi] = t; }7}8static void reflectTopBottom(int[][] g) {9for (int lo = 0, hi = g.length - 1; lo < hi; lo++, hi--) { int[] t = g[lo]; g[lo] = g[hi]; g[hi] = t; }10}11static void rotateClockwise(int[][] g) { transpose(g); reflectLeftRight(g); } // 90 degrees clockwise
Live state
R
3
C
3
Execution trace (dry run table)Show 12 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L11 | R=3 C=3 | A 90-degree clockwise rotation is a transpose followed by a left-right reflection of every row. |
| 2 | L3 | r=0 c=1 | g[0][1] and g[1][0] are mirror cells across the main diagonal. |
| 3 | L3 | swaps=1 | Swap g[0][1] with g[1][0]. |
| 4 | L3 | r=0 c=2 | g[0][2] and g[2][0] are mirror cells across the main diagonal. |
| 5 | L3 | swaps=2 | Swap g[0][2] with g[2][0]. |
| 6 | L3 | r=1 c=2 | g[1][2] and g[2][1] are mirror cells across the main diagonal. |
| 7 | L3 | swaps=3 | Swap g[1][2] with g[2][1]. |
| 8 | L11 | Transposed. Now reverse every row. | |
| 9 | L11 | swaps=4 | Row 0: swap columns 0 and 2. |
| 10 | L11 | swaps=5 | Row 1: swap columns 0 and 2. |
| 11 | L11 | swaps=6 | Row 2: swap columns 0 and 2. |
| 12 | L11 | swaps=6 return=[[7, 4, 1], [8, 5, 2], [9, 6, 3]] | 6 swaps, O(R x C) time and O(1) extra space (a non-square transpose needs a new matrix). |
Reflect
A left-right reflection reverses every row; a top-bottom reflection reverses the order of the rows. Both are O(R·C), in place, with no temporary matrix: swap pairs of cells (or of row references) from the outside in.
Try the non-square preset: reflections work on any rectangle, transpose in place does not.
1static void reflectLeftRight(int[][] g) {2for (int[] row : g)3for (int lo = 0, hi = row.length - 1; lo < hi; lo++, hi--) { int t = row[lo]; row[lo] = row[hi]; row[hi] = t; }4}5static void reflectTopBottom(int[][] g) {6for (int lo = 0, hi = g.length - 1; lo < hi; lo++, hi--) { int[] t = g[lo]; g[lo] = g[hi]; g[hi] = t; } // swaps whole rows7}
Transpose, reflect and rotate a matrix in place
Interactive · edit the inputgrid · 3 × 3
A 90-degree clockwise rotation is a transpose followed by a left-right reflection of every row.
1static void transpose(int[][] g) { // square matrix2for (int r = 0; r < g.length; r++)3for (int c = r + 1; c < g.length; c++) swap(g, r, c, c, r); // only above the diagonal4}5static void reflectLeftRight(int[][] g) {6for (int[] row : g) for (int lo = 0, hi = row.length - 1; lo < hi; lo++, hi--) { int t = row[lo]; row[lo] = row[hi]; row[hi] = t; }7}8static void reflectTopBottom(int[][] g) {9for (int lo = 0, hi = g.length - 1; lo < hi; lo++, hi--) { int[] t = g[lo]; g[lo] = g[hi]; g[hi] = t; }10}11static void rotateClockwise(int[][] g) { transpose(g); reflectLeftRight(g); } // 90 degrees clockwise
Live state
R
3
C
3
Execution trace (dry run table)Show 12 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L11 | R=3 C=3 | A 90-degree clockwise rotation is a transpose followed by a left-right reflection of every row. |
| 2 | L3 | r=0 c=1 | g[0][1] and g[1][0] are mirror cells across the main diagonal. |
| 3 | L3 | swaps=1 | Swap g[0][1] with g[1][0]. |
| 4 | L3 | r=0 c=2 | g[0][2] and g[2][0] are mirror cells across the main diagonal. |
| 5 | L3 | swaps=2 | Swap g[0][2] with g[2][0]. |
| 6 | L3 | r=1 c=2 | g[1][2] and g[2][1] are mirror cells across the main diagonal. |
| 7 | L3 | swaps=3 | Swap g[1][2] with g[2][1]. |
| 8 | L11 | Transposed. Now reverse every row. | |
| 9 | L11 | swaps=4 | Row 0: swap columns 0 and 2. |
| 10 | L11 | swaps=5 | Row 1: swap columns 0 and 2. |
| 11 | L11 | swaps=6 | Row 2: swap columns 0 and 2. |
| 12 | L11 | swaps=6 return=[[7, 4, 1], [8, 5, 2], [9, 6, 3]] | 6 swaps, O(R x C) time and O(1) extra space (a non-square transpose needs a new matrix). |
Rotate 90 degrees
Rotating a square matrix 90° clockwise equals transposing it and then reflecting every row left to right: cell (r, c) moves to (c, n - 1 - r). Counter-clockwise is the transpose followed by reversing the order of the rows. The in-place method uses O(1) extra space and O(n²) time.
The default animation rotates a 3 × 3 matrix in two phases.
1static void rotateClockwise(int[][] g) {2int n = g.length;3for (int r = 0; r < n; r++) for (int c = r + 1; c < n; c++) { int t = g[r][c]; g[r][c] = g[c][r]; g[c][r] = t; } // transpose4for (int[] row : g) for (int lo = 0, hi = n - 1; lo < hi; lo++, hi--) { int t = row[lo]; row[lo] = row[hi]; row[hi] = t; } // reverse rows5}
Transpose, reflect and rotate a matrix in place
Interactive · edit the inputgrid · 3 × 3
A 90-degree clockwise rotation is a transpose followed by a left-right reflection of every row.
1static void transpose(int[][] g) { // square matrix2for (int r = 0; r < g.length; r++)3for (int c = r + 1; c < g.length; c++) swap(g, r, c, c, r); // only above the diagonal4}5static void reflectLeftRight(int[][] g) {6for (int[] row : g) for (int lo = 0, hi = row.length - 1; lo < hi; lo++, hi--) { int t = row[lo]; row[lo] = row[hi]; row[hi] = t; }7}8static void reflectTopBottom(int[][] g) {9for (int lo = 0, hi = g.length - 1; lo < hi; lo++, hi--) { int[] t = g[lo]; g[lo] = g[hi]; g[hi] = t; }10}11static void rotateClockwise(int[][] g) { transpose(g); reflectLeftRight(g); } // 90 degrees clockwise
Live state
R
3
C
3
Execution trace (dry run table)Show 12 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L11 | R=3 C=3 | A 90-degree clockwise rotation is a transpose followed by a left-right reflection of every row. |
| 2 | L3 | r=0 c=1 | g[0][1] and g[1][0] are mirror cells across the main diagonal. |
| 3 | L3 | swaps=1 | Swap g[0][1] with g[1][0]. |
| 4 | L3 | r=0 c=2 | g[0][2] and g[2][0] are mirror cells across the main diagonal. |
| 5 | L3 | swaps=2 | Swap g[0][2] with g[2][0]. |
| 6 | L3 | r=1 c=2 | g[1][2] and g[2][1] are mirror cells across the main diagonal. |
| 7 | L3 | swaps=3 | Swap g[1][2] with g[2][1]. |
| 8 | L11 | Transposed. Now reverse every row. | |
| 9 | L11 | swaps=4 | Row 0: swap columns 0 and 2. |
| 10 | L11 | swaps=5 | Row 1: swap columns 0 and 2. |
| 11 | L11 | swaps=6 | Row 2: swap columns 0 and 2. |
| 12 | L11 | swaps=6 return=[[7, 4, 1], [8, 5, 2], [9, 6, 3]] | 6 swaps, O(R x C) time and O(1) extra space (a non-square transpose needs a new matrix). |
Matrix addition
Two matrices of the same shape add cell by cell: c[r][c] = a[r][c] + b[r][c], O(R·C) time. Subtraction and scalar multiplication work the same way. Different shapes cannot be added.
The animation adds a matrix to its own transpose.
1static int[][] add(int[][] a, int[][] b) {2int[][] c = new int[a.length][a[0].length];3for (int i = 0; i < a.length; i++)4for (int j = 0; j < a[0].length; j++) c[i][j] = a[i][j] + b[i][j];5return c;6}
Matrix addition and multiplication
Interactive · edit the inputgrid · 2 × 2
Each cell C[i][j] is the dot product of row i of A and column j of A: n multiplications and additions per cell.
1static int[][] add(int[][] a, int[][] b) { // same dimensions: O(n^2)2int[][] c = new int[a.length][a[0].length];3for (int i = 0; i < a.length; i++) for (int j = 0; j < a[0].length; j++) c[i][j] = a[i][j] + b[i][j];4return c;5}6static int[][] multiply(int[][] a, int[][] b) { // (n x m) times (m x p): O(n * m * p)7int[][] c = new int[a.length][b[0].length];8for (int i = 0; i < a.length; i++)9for (int j = 0; j < b[0].length; j++)10for (int k = 0; k < b.length; k++) c[i][j] += a[i][k] * b[k][j]; // row i of a dot column j of b11return c;12}
Live state
n
2
Execution trace (dry run table)Show 6 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L10 | n=2 | Each cell C[i][j] is the dot product of row i of A and column j of A: n multiplications and additions per cell. |
| 2 | L10 | i=0 j=0 C[0][0]=7 | C[0][0] = 1x1 + 2x3 = 7. |
| 3 | L10 | i=0 j=1 C[0][1]=10 | C[0][1] = 1x2 + 2x4 = 10. |
| 4 | L10 | i=1 j=0 C[1][0]=15 | C[1][0] = 3x1 + 4x3 = 15. |
| 5 | L10 | i=1 j=1 C[1][1]=22 | C[1][1] = 3x2 + 4x4 = 22. |
| 6 | L11 | return=[[7, 10], [15, 22]] | 4 cells x 2 multiplications = 8 multiplications: O(n³) for the standard algorithm. |
Matrix multiplication basics
An (n × m) matrix times an (m × p) matrix gives an (n × p) matrix where c[i][j] is the dot product of row i of A and column j of B. The standard algorithm uses three loops and costs O(n·m·p), O(n³) for square matrices. Matrix multiplication is not commutative, but it is associative, and Strassen's algorithm reduces the exponent to about 2.81.
Choose C = A × A and read the terms of each dot product.
1static int[][] multiply(int[][] a, int[][] b) { // (n x m) * (m x p)2int n = a.length, m = b.length, p = b[0].length;3int[][] c = new int[n][p];4for (int i = 0; i < n; i++)5for (int k = 0; k < m; k++) { // k before j: sequential access to b[k][*]6int aik = a[i][k];7for (int j = 0; j < p; j++) c[i][j] += aik * b[k][j];8}9return c;10}
Matrix addition and multiplication
Interactive · edit the inputgrid · 2 × 2
Each cell C[i][j] is the dot product of row i of A and column j of A: n multiplications and additions per cell.
1static int[][] add(int[][] a, int[][] b) { // same dimensions: O(n^2)2int[][] c = new int[a.length][a[0].length];3for (int i = 0; i < a.length; i++) for (int j = 0; j < a[0].length; j++) c[i][j] = a[i][j] + b[i][j];4return c;5}6static int[][] multiply(int[][] a, int[][] b) { // (n x m) times (m x p): O(n * m * p)7int[][] c = new int[a.length][b[0].length];8for (int i = 0; i < a.length; i++)9for (int j = 0; j < b[0].length; j++)10for (int k = 0; k < b.length; k++) c[i][j] += a[i][k] * b[k][j]; // row i of a dot column j of b11return c;12}
Live state
n
2
Execution trace (dry run table)Show 6 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L10 | n=2 | Each cell C[i][j] is the dot product of row i of A and column j of A: n multiplications and additions per cell. |
| 2 | L10 | i=0 j=0 C[0][0]=7 | C[0][0] = 1x1 + 2x3 = 7. |
| 3 | L10 | i=0 j=1 C[0][1]=10 | C[0][1] = 1x2 + 2x4 = 10. |
| 4 | L10 | i=1 j=0 C[1][0]=15 | C[1][0] = 3x1 + 4x3 = 15. |
| 5 | L10 | i=1 j=1 C[1][1]=22 | C[1][1] = 3x2 + 4x4 = 22. |
| 6 | L11 | return=[[7, 10], [15, 22]] | 4 cells x 2 multiplications = 8 multiplications: O(n³) for the standard algorithm. |
Practice ladder
Now try it yourself
Easy
- Transpose [[1, 2], [3, 4]] by hand
- How many swaps does an in-place transpose of an n × n matrix make?
Medium
- Rotate [[1, 2, 3], [4, 5, 6], [7, 8, 9]] clockwise using transpose + reflect
- Multiply [[1, 2], [3, 4]] by itself
Advanced
- Rotate a matrix in place by moving four cells at a time (layer by layer)
Key takeaways
- Traversals are O(R·C); prefer row order for speed.
- Rotate 90° clockwise = transpose, then reverse each row.
- Matrix multiplication is O(n·m·p) with a dot product per cell.