|
20 | 20 | function histogramArea(arr) {
|
21 | 21 | const histogram = arr;
|
22 | 22 |
|
23 |
| - // Generate combos |
24 |
| - const combos = []; |
25 |
| - for (let max = Math.pow(2, histogram.length), i = 0; i < max; i++) { |
26 |
| - let combo = i.toString(2); |
27 |
| - // Pad left |
28 |
| - while (combo.length < histogram.length) { |
29 |
| - combo = '0' + combo; |
30 |
| - } |
| 23 | + // 1s must be adjacent with no 0s in between |
| 24 | + const comboFilter = combo => /^[0]*[1]+[0]*$/.test(combo); |
31 | 25 |
|
32 |
| - // 1s must be adjacent with no 0s in between |
33 |
| - const goodComboRegEx = /^[0]*[1]+[0]*$/; |
34 |
| - const goodCombo = goodComboRegEx.test(combo); |
35 |
| - if (goodCombo) { |
36 |
| - combos.push(combo); |
37 |
| - } |
38 |
| - } |
| 26 | + const combos = ComboGenerator.generate(histogram.length, comboFilter); |
39 | 27 |
|
40 | 28 | let maxArea = 0;
|
41 |
| - combos.forEach(combo => { |
| 29 | + |
| 30 | + for (const combo of combos) { |
42 | 31 | const area = histogramAreaOfCombo(histogram, combo);
|
43 | 32 | if (area > maxArea) {
|
44 | 33 | maxArea = area;
|
45 | 34 | }
|
46 |
| - }); |
| 35 | + } |
47 | 36 |
|
48 | 37 | return maxArea;
|
49 | 38 | }
|
50 | 39 |
|
| 40 | +class ComboGenerator { |
| 41 | + /** |
| 42 | + * Function is a predicate to test each combination generated. Return true |
| 43 | + * to keep the element, false otherwise. |
| 44 | + * @callback filterCallback |
| 45 | + * @param {string} combo String represented. '0001', '0010', '0011', etc. |
| 46 | + */ |
| 47 | + |
| 48 | + /** |
| 49 | + * Returns generator of combinations as strings, '1' is on and '0' is off. |
| 50 | + * |
| 51 | + * `maxLength` is the number of binary digits to generate. Examples: |
| 52 | + * |
| 53 | + * 4: 0000 ... 1111 |
| 54 | + * 5: 00000 ... 11111 |
| 55 | + * 6: 000000 ... 111111 |
| 56 | + * @param {number} maxLength |
| 57 | + * @param {filterCallback} [filterCallback = () => true] |
| 58 | + * @return {Generator} |
| 59 | + */ |
| 60 | + static *generate(maxLength, filterCallback = () => true) { |
| 61 | + const max = Math.pow(2, maxLength); |
| 62 | + for (let i = 0; i < max; i++) { |
| 63 | + let combo = i.toString(2); |
| 64 | + // Pad left |
| 65 | + while (combo.length < maxLength) { |
| 66 | + combo = '0' + combo; |
| 67 | + } |
| 68 | + |
| 69 | + if (filterCallback(combo)) { |
| 70 | + yield combo; |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | +} |
| 75 | + |
51 | 76 | function histogramAreaOfCombo(histogram, combo) {
|
52 | 77 | const hist = histogram.filter((element, index) => combo[index] === '1');
|
53 | 78 | const maxHeight = Math.min(...hist);
|
|
0 commit comments