Вот мой вопрос:
Учитывая строку, состоящую из слов, разделенных пробелами, как я могу разбить это на N строк (грубой) четной длины, только разбивая пробелы?
Вот что я собрал из исследования:
Я начал с изучения алгоритмов обертывания слов, потому что мне кажется, что это в основном проблема с переносом слов. Тем не менее, большинство из того, что я нашел до сих пор (и есть много об обертывании слов), предполагает, что ширина линии является известным входом, а количество строк - результатом. Я хочу наоборот.
Я нашел (очень) несколько вопросов, таких как this, которые кажутся полезными. Тем не менее, все они сосредоточены на проблеме как одна из оптимизаций - например, как я могу разбить предложение на заданное количество строк, минимизируя рвение строк или потерянное пустое пространство или что-то в этом роде, и делаю это в линейном (или NlogN или любом другом) времени. Эти вопросы, как правило, остаются без ответа, поскольку оптимизационная часть проблемы относительно "жесткая".
Однако меня не волнует оптимизация. Пока строки (в большинстве случаев) примерно равны, я в порядке, если решение не работает в каждом случае с одним краем или не может быть доказано, что это наименьшая временная сложность. Мне просто нужно решение для реального мира, которое может взять строку и несколько строк (больше 2) и вернуть мне массив строк, которые обычно выглядят довольно даже.
Вот что я придумал: Я думаю, что у меня есть работоспособный метод для случая, когда N = 3. Я начинаю с первого слова на первой строке, последнего слова на последней строке, а затем итеративно помещаю другое слово в первую и последнюю строки, пока моя общая ширина (измеренная длиной самой длинной линии) перестанет становиться короче, Обычно это работает, но оно срабатывает, если ваши самые длинные слова находятся в середине строки, и это не кажется очень обобщаемым для более чем трех строк.
var getLongestHeaderLine = function(headerText) {
//Utility function definitions
var getLongest = function(arrayOfArrays) {
return arrayOfArrays.reduce(function(a, b) {
return a.length > b.length ? a : b;
});
};
var sumOfLengths = function(arrayOfArrays) {
return arrayOfArrays.reduce(function(a, b) {
return a + b.length + 1;
}, 0);
};
var getLongestLine = function(lines) {
return lines.reduce(function(a, b) {
return sumOfLengths(a) > sumOfLengths(b) ? a : b;
});
};
var getHeaderLength = function(lines) {
return sumOfLengths(getLongestLine(lines));
}
//first, deal with the degenerate cases
if (!headerText)
return headerText;
headerText = headerText.trim();
var headerWords = headerText.split(" ");
if (headerWords.length === 1)
return headerText;
if (headerWords.length === 2)
return getLongest(headerWords);
//If we have more than 2 words in the header,
//we need to split them into 3 lines
var firstLine = headerWords.splice(0, 1);
var lastLine = headerWords.splice(-1, 1);
var lines = [firstLine, headerWords, lastLine];
//The header length is the length of the longest
//line in the header. We will keep iterating
//until the header length stops getting shorter.
var headerLength = getHeaderLength(lines);
var lastHeaderLength = headerLength;
while (true) {
//Take the first word from the middle line,
//and add it to the first line
firstLine.push(headerWords.shift());
headerLength = getHeaderLength(lines);
if (headerLength > lastHeaderLength || headerWords.length === 0) {
//If we stopped getting shorter, undo
headerWords.unshift(firstLine.pop());
break;
}
//Take the last word from the middle line,
//and add it to the last line
lastHeaderLength = headerLength;
lastLine.unshift(headerWords.pop());
headerLength = getHeaderLength(lines);
if (headerLength > lastHeaderLength || headerWords.length === 0) {
//If we stopped getting shorter, undo
headerWords.push(lastLine.shift());
break;
}
lastHeaderLength = headerLength;
}
return getLongestLine(lines).join(" ");
};
debugger;
var header = "an apple a day keeps the doctor away";
var longestHeaderLine = getLongestHeaderLine(header);
debugger;
EDIT: я пометил javascript, потому что в конечном итоге мне хотелось бы, чтобы решение было реализовано на этом языке. Однако это не слишком критично для проблемы, и я бы принял любое решение, которое работает.
ИЗМЕНИТЬ № 2: Хотя производительность не в том, что меня больше всего волнует здесь, мне нужно иметь возможность выполнять любое решение, которое я придумываю, ~ 100-200 раз, для строк, которые могут содержать до 250 символов длинный. Это будет сделано во время загрузки страницы, поэтому его не нужно навсегда. Например, я обнаружил, что пытаясь разгрузить эту проблему в механизм рендеринга, поместив каждую строку в DIV, и игра с размерами не работает, поскольку она (кажется) невероятно дорога для измерения отображаемых элементов.