/*
Justify a string
Given an input string of words and spaces, and a desired line length n which is greater than or equal
to the length of the input string, output a string that differs only in whitespace from the original
string which meets the following requirements:
- the new string has length n
- no spaces before the first word
- no spaces after the last word
- the number of spaces between a pair of consecutive words differs by no more than 1 from the
number of spaces between any other pair of consecutive words.
For example, given the following inputs (using '-' instead of spaces for clarity):
str = "a-b-c-d" // length 7
n = 9 // length to justify the string to
The following outputs would be acceptable:
"a--b--c-d"
"a--b-c--d"
justify("a-b-c-d", 9) --> "a--b--c-d" (length 9)
However the following output would be unacceptable, because the number of spaces between words differs by more than 1:
"a---b-c-d"
function justify(str, n) {...}
assumptions:
n >= str.length
str does not start or end in spaces
*/
const SPACE = ' ';
function justify(str, target_length) {
const words = str.split(SPACE);
const spaces = [];
const { space, characters } = count(str);
const calculated_spaces = target_length - characters;
const multiplier = space > 0 ? Math.floor(calculated_spaces / space) : 0;
let remainder = calculated_spaces - (multiplier * space);
if (multiplier < 1) {
return str;
}
for (let i = 0; i < words.length - 1; i++) {
let repeat_count = multiplier;
if (remainder > 0) {
repeat_count++;
remainder--;
}
spaces.push(repeat(SPACE, repeat_count));
}
const justified = [];
for (let word of words) {
justified.push(word);
if (spaces.length > 0) {
justified.push(spaces.shift());
}
}
return justified.join('');
}
function count(str) {
let space_count = 0;
let char_count = 0;
for (let i = 0; i < str.length; i++) {
if (str.charAt(i) === SPACE) {
space_count++;
} else {
char_count++;
}
}
return {
space: space_count,
characters: char_count,
};
}
function repeat(str, count) {
let output = '';
for (let i = 0; i < count; i++) {
output += str;
}
return output;
}
function test({ str, length }, expected) {
const actual = justify(str, length);
if (actual === expected) {
console.log(` [ok]: '${actual}' (length: ${length})`);
} else {
console.log(`[fail] '${actual}' != '${expected}'`);
}
}
console.log('test');
test({ str: 'a b c d', length: 9 }, 'a b c d');
test({ str: 'a b c', length: 7 }, 'a b c');
test({ str: 'hello', length: 7 }, 'hello');
test({ str: 'hello', length: 5 }, 'hello');
test({ str: '1 2 3 4', length: 9 }, '1 2 3 4');
test({ str: '1 2 3 4', length: 10 }, '1 2 3 4');
test({ str: '1 2 3 4', length: 11 }, '1 2 3 4');
test({ str: '11 22', length: 10 }, '11 22');
test({ str: '11 22', length: 6 }, '11 22');
test({ str: '1 1 2 2', length: 9 }, '1 1 2 2');