Skip to content

Commit 1ad4843

Browse files
committed
feat: text-justification-dp challenge
1 parent 39c42d7 commit 1ad4843

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Challenge: Given a set of words and a maximum width, implement a dynamic programming algorithm
2+
# to justify text optimally, minimizing penalties for irregular spaces.
3+
# Use object-oriented programming and follow the DRY principle.
4+
5+
from text_justifier import TextJustifier
6+
7+
def main():
8+
words = ["This", "is", "an", "example", "of", "text", "justification."]
9+
max_width = 16
10+
justifier = TextJustifier(words, max_width)
11+
justified_text = justifier.justify()
12+
for line in justified_text:
13+
print(f'"{line}"')
14+
15+
if __name__ == "__main__":
16+
main()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from typing import List
2+
3+
class TextJustifier:
4+
def __init__(self, words: List[str], max_width: int):
5+
self.words = words
6+
self.max_width = max_width
7+
self.n = len(words)
8+
self.dp = [float('inf')] * (self.n + 1)
9+
self.dp[self.n] = 0
10+
self.breaks = [-1] * (self.n + 1)
11+
12+
def _cost(self, i: int, j: int) -> float:
13+
length = sum(len(self.words[k]) for k in range(i, j + 1)) + (j - i)
14+
if length > self.max_width:
15+
return float('inf')
16+
return (self.max_width - length) ** 3
17+
18+
def justify(self) -> List[str]:
19+
for i in range(self.n - 1, -1, -1):
20+
for j in range(i, self.n):
21+
cost = self._cost(i, j)
22+
if cost == float('inf'):
23+
break
24+
if self.dp[j + 1] + cost < self.dp[i]:
25+
self.dp[i] = self.dp[j + 1] + cost
26+
self.breaks[i] = j
27+
28+
lines = []
29+
i = 0
30+
while i < self.n:
31+
j = self.breaks[i]
32+
line_words = self.words[i:j + 1]
33+
line = self._justify_line(line_words)
34+
lines.append(line)
35+
i = j + 1
36+
return lines
37+
38+
def _justify_line(self, line_words: List[str]) -> str:
39+
if len(line_words) == 1:
40+
return line_words[0] + ' ' * (self.max_width - len(line_words[0]))
41+
42+
total_spaces = self.max_width - sum(len(word) for word in line_words)
43+
spaces_between_words = len(line_words) - 1
44+
space, extra = divmod(total_spaces, spaces_between_words)
45+
46+
line = ''
47+
for i, word in enumerate(line_words[:-1]):
48+
line += word + ' ' * (space + (1 if i < extra else 0))
49+
line += line_words[-1]
50+
return line

0 commit comments

Comments
 (0)