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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy