Python/strings/text_justification.py
pre-commit-ci[bot] 716bdeb68b
[pre-commit.ci] pre-commit autoupdate (#11473)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.10 → v0.5.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.10...v0.5.0)
- [github.com/pre-commit/mirrors-mypy: v1.10.0 → v1.10.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.0...v1.10.1)

* Fix ruff issues

* Fix ruff issues

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Christian Clauss <cclauss@me.com>
2024-07-02 07:02:29 +02:00

92 lines
3.5 KiB
Python

def text_justification(word: str, max_width: int) -> list:
"""
Will format the string such that each line has exactly
(max_width) characters and is fully (left and right) justified,
and return the list of justified text.
example 1:
string = "This is an example of text justification."
max_width = 16
output = ['This is an',
'example of text',
'justification. ']
>>> text_justification("This is an example of text justification.", 16)
['This is an', 'example of text', 'justification. ']
example 2:
string = "Two roads diverged in a yellow wood"
max_width = 16
output = ['Two roads',
'diverged in a',
'yellow wood ']
>>> text_justification("Two roads diverged in a yellow wood", 16)
['Two roads', 'diverged in a', 'yellow wood ']
Time complexity: O(m*n)
Space complexity: O(m*n)
"""
# Converting string into list of strings split by a space
words = word.split()
def justify(line: list, width: int, max_width: int) -> str:
overall_spaces_count = max_width - width
words_count = len(line)
if len(line) == 1:
# if there is only word in line
# just insert overall_spaces_count for the remainder of line
return line[0] + " " * overall_spaces_count
else:
spaces_to_insert_between_words = words_count - 1
# num_spaces_between_words_list[i] : tells you to insert
# num_spaces_between_words_list[i] spaces
# after word on line[i]
num_spaces_between_words_list = spaces_to_insert_between_words * [
overall_spaces_count // spaces_to_insert_between_words
]
spaces_count_in_locations = (
overall_spaces_count % spaces_to_insert_between_words
)
# distribute spaces via round robin to the left words
for i in range(spaces_count_in_locations):
num_spaces_between_words_list[i] += 1
aligned_words_list = []
for i in range(spaces_to_insert_between_words):
# add the word
aligned_words_list.append(line[i])
# add the spaces to insert
aligned_words_list.append(num_spaces_between_words_list[i] * " ")
# just add the last word to the sentence
aligned_words_list.append(line[-1])
# join the aligned words list to form a justified line
return "".join(aligned_words_list)
answer = []
line: list[str] = []
width = 0
for inner_word in words:
if width + len(inner_word) + len(line) <= max_width:
# keep adding words until we can fill out max_width
# width = sum of length of all words (without overall_spaces_count)
# len(inner_word) = length of current inner_word
# len(line) = number of overall_spaces_count to insert between words
line.append(inner_word)
width += len(inner_word)
else:
# justify the line and add it to result
answer.append(justify(line, width, max_width))
# reset new line and new width
line, width = [inner_word], len(inner_word)
remaining_spaces = max_width - width - len(line)
answer.append(" ".join(line) + (remaining_spaces + 1) * " ")
return answer
if __name__ == "__main__":
from doctest import testmod
testmod()