Skip to content

Commit 55e6d89

Browse files
committed
Added hard/matrix_determinant
1 parent 8fb6936 commit 55e6d89

File tree

2 files changed

+302
-0
lines changed

2 files changed

+302
-0
lines changed

hard/matrix_determinant.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/**
2+
* Using the JavaScript language, have the function matrixDeterminant(strArr)
3+
* read strArr which will be an array of integers represented as strings. Within
4+
* the array there will also be "<>" elements which represent break points. The
5+
* array will make up a matrix where the (number of break points + 1) represents
6+
* the number of rows. Here is an example of how strArr may look:
7+
* ["1","2","<>","3","4"]. The contents of this array are row1=[1 2] and row2=[3
8+
* 4]. Your program should take the given array of elements, create the proper
9+
* matrix, and then calculate the determinant. For the example above, your
10+
* program should return -2. If the matrix is not a square matrix, return -1.
11+
* The maximum size of strArr will be a 6x6 matrix. The determinant will always
12+
* be an integer.
13+
*
14+
* https://www.coderbyte.com/results/bhanson:Matrix%20Determinant:JavaScript
15+
*
16+
* @param {array} strArr
17+
* @return {number}
18+
*/
19+
function matrixDeterminant(strArr) {
20+
const matrixLength = Math.floor(Math.sqrt(strArr.length));
21+
22+
// Input array must be square
23+
// 1x1 = 1 + 0 = 1
24+
// 2x2 = 4 + 1 = 5
25+
// 3x3 = 9 + 2 = 11
26+
// 4x4 = 16 + 3 = 19
27+
// 5x5 = 25 + 4 = 29
28+
// 6x6 = 36 + 5 = 41
29+
// ...
30+
if (matrixLength * matrixLength + (matrixLength - 1) !== strArr.length) {
31+
return -1;
32+
}
33+
34+
// Remove separators and cast to number
35+
const cells = strArr.filter(element => element !== '<>').map(Number);
36+
37+
const matrix = buildMatrix(matrixLength, matrixLength);
38+
fillMatrix(matrix, cells);
39+
40+
// https://en.wikipedia.org/wiki/Determinant
41+
const determinant = matrixDeterminantRecursive(matrix);
42+
return determinant;
43+
}
44+
45+
// Returns reference to new empty matrix
46+
function buildMatrix(rows, columns, fillValue = 0) {
47+
const newMatrix = Array(rows)
48+
.fill(0)
49+
.map(_ => Array(columns).fill(fillValue));
50+
return newMatrix;
51+
}
52+
53+
// Fill 2d matrix with 1d array
54+
function fillMatrix(matrix, arrElements) {
55+
const rows = matrix.length;
56+
const columns = matrix[0].length;
57+
58+
if (arrElements.length !== rows * columns) {
59+
return undefined;
60+
}
61+
62+
arrElements.forEach((element, index) => {
63+
const rowIndex = Math.floor(index / rows);
64+
const colIndex = index % columns;
65+
matrix[rowIndex][colIndex] = element;
66+
});
67+
}
68+
69+
// Finds determinant of any sized matrix, recursively
70+
function matrixDeterminantRecursive(matrix) {
71+
const rows = matrix.length;
72+
const columns = matrix[0].length;
73+
74+
if (rows === 2 && columns === 2) {
75+
return matrixDeterminant2x2(matrix);
76+
}
77+
78+
let subDeterminants = [];
79+
for (let i = 0; i < columns; i++) {
80+
const subMatrix = reduceMatrix(matrix, [0], [i]);
81+
const subDeterminant = matrixDeterminantRecursive(subMatrix);
82+
subDeterminants.push(matrix[0][i] * subDeterminant);
83+
}
84+
85+
// + - + - ... pattern
86+
subDeterminants = subDeterminants.map((determinant, index) => {
87+
const polarity = index % 2 === 0 ? 1 : -1;
88+
return determinant * polarity;
89+
});
90+
91+
const sum = subDeterminants.reduce((sum, value) => (sum += value), 0);
92+
93+
return sum;
94+
}
95+
96+
// Returns determinant of 2x2 matrix
97+
function matrixDeterminant2x2(matrix) {
98+
const rows = matrix.length;
99+
const columns = matrix[0].length;
100+
101+
if (columns !== 2 || rows !== 2) {
102+
return undefined;
103+
}
104+
105+
const [a, b] = matrix[0];
106+
const [c, d] = matrix[1];
107+
108+
const determinant = a * d - b * c;
109+
110+
return determinant;
111+
}
112+
113+
// Returns a new matrix without specified rows or columns
114+
function reduceMatrix(matrix, ignoreRows, ignoreColumns) {
115+
const rows = matrix.length;
116+
const columns = matrix[0].length;
117+
118+
let newMatrix = copyMatrix(matrix);
119+
120+
// `null` out values to be ignored
121+
newMatrix.forEach((row, rowIndex) => {
122+
if (ignoreRows.includes(rowIndex)) {
123+
newMatrix[rowIndex] = null;
124+
} else {
125+
row.forEach((value, colIndex) => {
126+
if (ignoreColumns.includes(colIndex)) {
127+
newMatrix[rowIndex][colIndex] = null;
128+
}
129+
});
130+
}
131+
});
132+
133+
// remove `null` valued rows
134+
newMatrix = newMatrix.filter(row => row !== null);
135+
136+
// remove `null` valued columns
137+
newMatrix = newMatrix.map(row => row.filter(col => col !== null));
138+
139+
return newMatrix;
140+
}
141+
142+
// Performs a deep copy of a 2d array
143+
function copyMatrix(matrix) {
144+
const rows = matrix.length;
145+
const columns = matrix[0].length;
146+
const newMatrix = buildMatrix(rows, columns);
147+
matrix.forEach((row, rowIndex) => {
148+
row.forEach((value, colIndex) => {
149+
newMatrix[rowIndex][colIndex] = value;
150+
});
151+
});
152+
return newMatrix;
153+
}
154+
155+
module.exports = matrixDeterminant;

hard/matrix_determinant.test.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
const matrixDeterminant = require('./matrix_determinant');
2+
3+
describe('matrixDeterminant()', () => {
4+
test('passes Coderbyte.com tests', () => {
5+
expect(
6+
matrixDeterminant([
7+
'1',
8+
'2',
9+
'4',
10+
'<>',
11+
'2',
12+
'1',
13+
'1',
14+
'<>',
15+
'4',
16+
'1',
17+
'1'
18+
])
19+
).toBe(-4);
20+
21+
expect(matrixDeterminant(['1', '2', '<>', '3', '4'])).toBe(-2);
22+
23+
expect(matrixDeterminant(['5', '0', '<>', '0', '5'])).toBe(25);
24+
25+
expect(
26+
matrixDeterminant([
27+
'1',
28+
'2',
29+
'4',
30+
'<>',
31+
'2',
32+
'1',
33+
'1',
34+
'<>',
35+
'4',
36+
'5',
37+
'5'
38+
])
39+
).toBe(12);
40+
41+
expect(
42+
matrixDeterminant(['1', '2', '<>', '2', '1', '<>', '1', '1', '1'])
43+
).toBe(-1);
44+
45+
expect(matrixDeterminant(['1', '0', '<>', '1', '0'])).toBe(0);
46+
47+
expect(
48+
matrixDeterminant([
49+
'-1',
50+
'-1',
51+
'-1',
52+
'<>',
53+
'0',
54+
'9',
55+
'100',
56+
'<>',
57+
'2',
58+
'3',
59+
'5'
60+
])
61+
).toBe(73);
62+
63+
expect(
64+
matrixDeterminant([
65+
'1',
66+
'2',
67+
'3',
68+
'4',
69+
'5',
70+
'<>',
71+
'2',
72+
'2',
73+
'4',
74+
'5',
75+
'6',
76+
'<>',
77+
'3',
78+
'4',
79+
'4',
80+
'5',
81+
'6',
82+
'<>',
83+
'4',
84+
'5',
85+
'5',
86+
'0',
87+
'1',
88+
'<>',
89+
'5',
90+
'6',
91+
'6',
92+
'1',
93+
'1'
94+
])
95+
).toBe(43);
96+
97+
expect(
98+
matrixDeterminant([
99+
'1000',
100+
'2',
101+
'3',
102+
'4',
103+
'5',
104+
'<>',
105+
'2',
106+
'2',
107+
'4',
108+
'5',
109+
'6',
110+
'<>',
111+
'3',
112+
'4',
113+
'4',
114+
'5',
115+
'6',
116+
'<>',
117+
'4',
118+
'5',
119+
'5',
120+
'0',
121+
'1',
122+
'<>',
123+
'5',
124+
'6',
125+
'6',
126+
'1',
127+
'1000'
128+
])
129+
).toBe(49801192);
130+
131+
expect(
132+
matrixDeterminant([
133+
'-6',
134+
'1',
135+
'-6',
136+
'<>',
137+
'-1',
138+
'-1',
139+
'-1',
140+
'<>',
141+
'1',
142+
'1',
143+
'2'
144+
])
145+
).toBe(7);
146+
});
147+
});

0 commit comments

Comments
 (0)