Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7f90fdd

Browse files
feat(js): add modular solution and documentation for hard challenge 9 - Text Justification with DP
1 parent e7bb4e6 commit 7f90fdd

File tree

3 files changed

+255
-0
lines changed

3 files changed

+255
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Text Justification with Dynamic Programming
2+
3+
## English
4+
5+
Text justification is a classic problem in document formatting and typesetting. Dynamic programming provides an optimal solution by minimizing the penalty of uneven spacing, improving readability and aesthetics.
6+
7+
This challenge involves implementing a dynamic programming algorithm to justify text optimally, minimizing penalties for irregular spaces.
8+
9+
### Relevant Code Snippet
10+
11+
```javascript
12+
class TextJustifier {
13+
constructor(words, maxWidth) {
14+
this.words = words;
15+
this.maxWidth = maxWidth;
16+
this.n = words.length;
17+
this.dp = new Array(this.n + 1).fill(Infinity);
18+
this.dp[this.n] = 0;
19+
this.breaks = new Array(this.n + 1).fill(-1);
20+
}
21+
22+
_cost(i, j) {
23+
const length =
24+
this.words.slice(i, j + 1).reduce((acc, w) => acc + w.length, 0) +
25+
(j - i);
26+
if (length > this.maxWidth) {
27+
return Infinity;
28+
}
29+
return Math.pow(this.maxWidth - length, 3);
30+
}
31+
32+
justify() {
33+
for (let i = this.n - 1; i >= 0; i--) {
34+
for (let j = i; j < this.n; j++) {
35+
const cost = this._cost(i, j);
36+
if (cost === Infinity) {
37+
break;
38+
}
39+
if (this.dp[j + 1] + cost < this.dp[i]) {
40+
this.dp[i] = this.dp[j + 1] + cost;
41+
this.breaks[i] = j;
42+
}
43+
}
44+
}
45+
46+
const lines = [];
47+
let i = 0;
48+
while (i < this.n) {
49+
const j = this.breaks[i];
50+
const lineWords = this.words.slice(i, j + 1);
51+
const line = this._justifyLine(lineWords);
52+
lines.push(line);
53+
i = j + 1;
54+
}
55+
return lines;
56+
}
57+
58+
_justifyLine(lineWords) {
59+
if (lineWords.length === 1) {
60+
return lineWords[0] + " ".repeat(this.maxWidth - lineWords[0].length);
61+
}
62+
63+
const totalSpaces =
64+
this.maxWidth - lineWords.reduce((acc, w) => acc + w.length, 0);
65+
const spacesBetweenWords = lineWords.length - 1;
66+
const space = Math.floor(totalSpaces / spacesBetweenWords);
67+
const extra = totalSpaces % spacesBetweenWords;
68+
69+
let line = "";
70+
for (let i = 0; i < lineWords.length - 1; i++) {
71+
line += lineWords[i] + " ".repeat(space + (i < extra ? 1 : 0));
72+
}
73+
line += lineWords[lineWords.length - 1];
74+
return line;
75+
}
76+
}
77+
```
78+
79+
### History
80+
81+
Text justification has been extensively studied in document formatting and typesetting, with dynamic programming providing an optimal solution to improve readability and aesthetics.
82+
83+
---
84+
85+
## Español
86+
87+
Justificación de Texto con Programación Dinámica
88+
89+
La justificación de texto es un problema clásico en el formateo y composición de documentos. La programación dinámica proporciona una solución óptima al minimizar la penalización por espacios desiguales, mejorando la legibilidad y estética.
90+
91+
Este reto consiste en implementar un algoritmo de programación dinámica para justificar texto de manera óptima, minimizando penalizaciones por espacios irregulares.
92+
93+
### Fragmento de Código Relevante
94+
95+
```javascript
96+
class TextJustifier {
97+
constructor(words, maxWidth) {
98+
this.words = words;
99+
this.maxWidth = maxWidth;
100+
this.n = words.length;
101+
this.dp = new Array(this.n + 1).fill(Infinity);
102+
this.dp[this.n] = 0;
103+
this.breaks = new Array(this.n + 1).fill(-1);
104+
}
105+
106+
_cost(i, j) {
107+
const length =
108+
this.words.slice(i, j + 1).reduce((acc, w) => acc + w.length, 0) +
109+
(j - i);
110+
if (length > this.maxWidth) {
111+
return Infinity;
112+
}
113+
return Math.pow(this.maxWidth - length, 3);
114+
}
115+
116+
justify() {
117+
for (let i = this.n - 1; i >= 0; i--) {
118+
for (let j = i; j < this.n; j++) {
119+
const cost = this._cost(i, j);
120+
if (cost === Infinity) {
121+
break;
122+
}
123+
if (this.dp[j + 1] + cost < this.dp[i]) {
124+
this.dp[i] = this.dp[j + 1] + cost;
125+
this.breaks[i] = j;
126+
}
127+
}
128+
}
129+
130+
const lines = [];
131+
let i = 0;
132+
while (i < this.n) {
133+
const j = this.breaks[i];
134+
const lineWords = this.words.slice(i, j + 1);
135+
const line = this._justifyLine(lineWords);
136+
lines.push(line);
137+
i = j + 1;
138+
}
139+
return lines;
140+
}
141+
142+
_justifyLine(lineWords) {
143+
if (lineWords.length === 1) {
144+
return lineWords[0] + " ".repeat(this.maxWidth - lineWords[0].length);
145+
}
146+
147+
const totalSpaces =
148+
this.maxWidth - lineWords.reduce((acc, w) => acc + w.length, 0);
149+
const spacesBetweenWords = lineWords.length - 1;
150+
const space = Math.floor(totalSpaces / spacesBetweenWords);
151+
const extra = totalSpaces % spacesBetweenWords;
152+
153+
let line = "";
154+
for (let i = 0; i < lineWords.length - 1; i++) {
155+
line += lineWords[i] + " ".repeat(space + (i < extra ? 1 : 0));
156+
}
157+
line += lineWords[lineWords.length - 1];
158+
return line;
159+
}
160+
}
161+
```
162+
163+
### Historia
164+
165+
La justificación de texto ha sido ampliamente estudiada en el formateo y composición de documentos, y la programación dinámica proporciona una solución óptima para mejorar la legibilidad y estética.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// TextJustifier.js - Text Justification using Dynamic Programming in JavaScript
2+
3+
class TextJustifier {
4+
constructor(words, maxWidth) {
5+
this.words = words;
6+
this.maxWidth = maxWidth;
7+
this.n = words.length;
8+
this.dp = new Array(this.n + 1).fill(Infinity);
9+
this.dp[this.n] = 0;
10+
this.breaks = new Array(this.n + 1).fill(-1);
11+
}
12+
13+
_cost(i, j) {
14+
const length =
15+
this.words.slice(i, j + 1).reduce((acc, w) => acc + w.length, 0) +
16+
(j - i);
17+
if (length > this.maxWidth) {
18+
return Infinity;
19+
}
20+
return Math.pow(this.maxWidth - length, 3);
21+
}
22+
23+
justify() {
24+
for (let i = this.n - 1; i >= 0; i--) {
25+
for (let j = i; j < this.n; j++) {
26+
const cost = this._cost(i, j);
27+
if (cost === Infinity) {
28+
break;
29+
}
30+
if (this.dp[j + 1] + cost < this.dp[i]) {
31+
this.dp[i] = this.dp[j + 1] + cost;
32+
this.breaks[i] = j;
33+
}
34+
}
35+
}
36+
37+
const lines = [];
38+
let i = 0;
39+
while (i < this.n) {
40+
const j = this.breaks[i];
41+
const lineWords = this.words.slice(i, j + 1);
42+
const line = this._justifyLine(lineWords);
43+
lines.push(line);
44+
i = j + 1;
45+
}
46+
return lines;
47+
}
48+
49+
_justifyLine(lineWords) {
50+
if (lineWords.length === 1) {
51+
return lineWords[0] + " ".repeat(this.maxWidth - lineWords[0].length);
52+
}
53+
54+
const totalSpaces =
55+
this.maxWidth - lineWords.reduce((acc, w) => acc + w.length, 0);
56+
const spacesBetweenWords = lineWords.length - 1;
57+
const space = Math.floor(totalSpaces / spacesBetweenWords);
58+
const extra = totalSpaces % spacesBetweenWords;
59+
60+
let line = "";
61+
for (let i = 0; i < lineWords.length - 1; i++) {
62+
line += lineWords[i] + " ".repeat(space + (i < extra ? 1 : 0));
63+
}
64+
line += lineWords[lineWords.length - 1];
65+
return line;
66+
}
67+
}
68+
69+
export default TextJustifier;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
Challenge:
3+
Given a set of words and a maximum width, implement a dynamic programming algorithm to justify text optimally, minimizing penalties for irregular spaces.
4+
5+
This solution follows DRY principles and is implemented in JavaScript.
6+
*/
7+
8+
import TextJustifier from "./TextJustifier.js";
9+
10+
function main() {
11+
const words = ["This", "is", "an", "example", "of", "text", "justification."];
12+
const maxWidth = 16;
13+
14+
const justifier = new TextJustifier(words, maxWidth);
15+
const justifiedLines = justifier.justify();
16+
17+
console.log("Justified Text:");
18+
justifiedLines.forEach((line) => console.log(`"${line}"`));
19+
}
20+
21+
main();

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /