From 75133592bb0ca7ff7ededf80d927f179e6b41b8e Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 6 Jul 2018 08:15:56 +0300 Subject: [PATCH] Add square matrix rotation in-place algorithm. --- README.md | 1 + .../square-matrix-rotation/README.md | 90 +++++++++++++++++++ .../__test__/squareMatrixRotation.test.js | 59 ++++++++++++ .../squareMatrixRotation.js | 28 ++++++ 4 files changed, 178 insertions(+) create mode 100644 src/algorithms/uncategorized/square-matrix-rotation/README.md create mode 100644 src/algorithms/uncategorized/square-matrix-rotation/__test__/squareMatrixRotation.test.js create mode 100644 src/algorithms/uncategorized/square-matrix-rotation/squareMatrixRotation.js diff --git a/README.md b/README.md index 9899814e..f6730d39 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) + * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm ### Algorithms by Paradigm diff --git a/src/algorithms/uncategorized/square-matrix-rotation/README.md b/src/algorithms/uncategorized/square-matrix-rotation/README.md new file mode 100644 index 00000000..4c16e16d --- /dev/null +++ b/src/algorithms/uncategorized/square-matrix-rotation/README.md @@ -0,0 +1,90 @@ +# Square Matrix In-Place Rotation + +## The Problem + +You are given an `n x n` 2D matrix (representing an image). +Rotate the matrix by `90` degrees (clockwise). + +**Note** + +You have to rotate the image **in-place**, which means you +have to modify the input 2D matrix directly. **DO NOT** allocate +another 2D matrix and do the rotation. + +## Examples + +**Example #1** + +Given input matrix: + +``` +[ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +] +``` + +Rotate the input matrix in-place such that it becomes: + +``` +[ + [7, 4, 1], + [8, 5, 2], + [9, 6, 3], +] +``` + +**Example #2** + +Given input matrix: + +``` +[ + [5, 1, 9, 11], + [2, 4, 8, 10], + [13, 3, 6, 7], + [15, 14, 12, 16], +] +``` + +Rotate the input matrix in-place such that it becomes: + +``` +[ + [15, 13, 2, 5], + [14, 3, 4, 1], + [12, 6, 8, 9], + [16, 7, 10, 11], +] +``` + +## Algorithm + +We would need to do two reflections of the matrix: + +- reflect vertically +- reflect diagonally from bottom-left to top-right + +Or we also could Furthermore, you can reflect diagonally +top-left/bottom-right and reflect horizontally. + +A common question is how do you even figure out what kind +of reflections to do? Simply rip a square piece of paper, +write a random word on it so you know its rotation. Then, +flip the square piece of paper around until you figure out +how to come to the solution. + +Here is an example of how first line may be rotated using +diagonal top-right/bottom-left rotation along with horizontal +rotation. + +``` +A B C A - - . . A +/ / --> B - - --> . . B +/ . . C - - . . C +``` + +## References + +- [LeetCode](https://leetcode.com/problems/rotate-image/description/) diff --git a/src/algorithms/uncategorized/square-matrix-rotation/__test__/squareMatrixRotation.test.js b/src/algorithms/uncategorized/square-matrix-rotation/__test__/squareMatrixRotation.test.js new file mode 100644 index 00000000..cb22a9c9 --- /dev/null +++ b/src/algorithms/uncategorized/square-matrix-rotation/__test__/squareMatrixRotation.test.js @@ -0,0 +1,59 @@ +import squareMatrixRotation from '../squareMatrixRotation'; + +describe('squareMatrixRotation', () => { + it('should rotate matrix #0 in-place', () => { + const matrix = [[1]]; + + const rotatedMatrix = [[1]]; + + expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix); + }); + + it('should rotate matrix #1 in-place', () => { + const matrix = [ + [1, 2], + [3, 4], + ]; + + const rotatedMatrix = [ + [3, 1], + [4, 2], + ]; + + expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix); + }); + + it('should rotate matrix #2 in-place', () => { + const matrix = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ]; + + const rotatedMatrix = [ + [7, 4, 1], + [8, 5, 2], + [9, 6, 3], + ]; + + expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix); + }); + + it('should rotate matrix #3 in-place', () => { + const matrix = [ + [5, 1, 9, 11], + [2, 4, 8, 10], + [13, 3, 6, 7], + [15, 14, 12, 16], + ]; + + const rotatedMatrix = [ + [15, 13, 2, 5], + [14, 3, 4, 1], + [12, 6, 8, 9], + [16, 7, 10, 11], + ]; + + expect(squareMatrixRotation(matrix)).toEqual(rotatedMatrix); + }); +}); diff --git a/src/algorithms/uncategorized/square-matrix-rotation/squareMatrixRotation.js b/src/algorithms/uncategorized/square-matrix-rotation/squareMatrixRotation.js new file mode 100644 index 00000000..139c73ec --- /dev/null +++ b/src/algorithms/uncategorized/square-matrix-rotation/squareMatrixRotation.js @@ -0,0 +1,28 @@ +/** + * @param {*[][]} originalMatrix + * @return {*[][]} + */ +export default function squareMatrixRotation(originalMatrix) { + const matrix = originalMatrix.slice(); + + // Do top-right/bottom-left diagonal reflection of the matrix. + for (let rowIndex = 0; rowIndex < matrix.length; rowIndex += 1) { + for (let columnIndex = rowIndex + 1; columnIndex < matrix.length; columnIndex += 1) { + const tmp = matrix[columnIndex][rowIndex]; + matrix[columnIndex][rowIndex] = matrix[rowIndex][columnIndex]; + matrix[rowIndex][columnIndex] = tmp; + } + } + + // Do horizontal reflection of the matrix. + for (let rowIndex = 0; rowIndex < matrix.length; rowIndex += 1) { + for (let columnIndex = 0; columnIndex < matrix.length / 2; columnIndex += 1) { + const mirrorColumnIndex = matrix.length - columnIndex - 1; + const tmp = matrix[rowIndex][mirrorColumnIndex]; + matrix[rowIndex][mirrorColumnIndex] = matrix[rowIndex][columnIndex]; + matrix[rowIndex][columnIndex] = tmp; + } + } + + return matrix; +}