如何减少代码的运行时间以对齐文本?

How do I reduce the running time of the code to justify text?

本文关键字:对齐 文本 运行时间 何减少 代码      更新时间:2023-10-16

简而言之,这是问题陈述:

给定一个单词数组和一个宽度 maxWidth,设置文本格式,使每行都具有恰好 maxWidth 字符,并且完全(左右(对齐。 你应该以贪婪的方式包装你的话;也就是说,在每行中尽可能多地包含单词。必要时填充额外的空格 ' ',以便每行都有恰好 maxWidth 字符。 单词之间的额外空格应尽可能均匀地分布。如果一行上的空格数在单词之间分配不均匀,则左侧的空插槽将分配比右侧的插槽更多的空间。 对于文本的最后一行,应将其左对齐,并且在单词之间不插入多余的空格。

这是我为证明文本的合理性而编写的代码:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
std::vector<std::string> getWords(std::string line) {
std::istringstream iss(line);
return std::vector<std::string>{ std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{} };
}
std::vector<std::string> justifiedText(const std::vector<std::string>& text, const size_t& width) {
std::vector<std::string> list_of_words;
for (const auto& line : text) {
auto words = getWords(line);
for (const auto& word : words) {
list_of_words.push_back(word);
}
}
//divide into lines
std::vector<std::string> justify;
for (int i = 0; i < list_of_words.size(); i++) {
std::string statement;
while (statement.size() + list_of_words.at(i).size() <= width) {
statement = statement + list_of_words.at(i) + " ";
i++;
if (i == list_of_words.size()) {
break;
}
}
statement.erase(--statement.end());
justify.push_back(statement);
i--;
}
for (int i = 0; i < justify.size() - 1; i++) {
std::string& statement = justify.at(i);
int j = 0;
int extra_spaces = 0;
while (statement.size() < 16) {
if (statement.at(j) == ' ') {
statement.insert(j, " ");
j = j + ++extra_spaces;
}
j = j >= statement.size() - 1 ? 0 : j + 1;
}
}
auto& statement = justify.back();
while (statement.size() < 16) {
statement += " ";
}
return justify;
}
int main() {
//I/O is through file as my lazy ass finds it exhausting to type in the console over and over again :P
std::ifstream infile("ip.txt");
int width = 0;
infile >> width;
int count_of_lines = 0;
infile >> count_of_lines;
std::vector<std::string> text(count_of_lines);
{
std::string str;
std::getline(infile, str, 'n');
}
for (auto& line : text) {
std::getline(infile, line, 'n');
}
infile.close();
text = justifiedText(text, width);
std::ofstream outfile("output.txt");
for (auto line : text) {
outfile << line << "n";
}
outfile.close();
return 0;
}

此代码通过此处显示的测试用例,但超过了所有剩余测试用例的时间限制。如何提高代码的运行时间/时间复杂度?

附言这似乎是一个xy problem,因此欢迎替代解决方案:)

链接的问题陈述以

给定一个单词数组和一个宽度 maxWidth

在发布的代码中,函数justifiedText首先遍历作为参数传递的向量,就好像它由多个单词的行组成,提取并复制到新的向量中(使用stringstream临时(。

返回向量中的每个字符串都由附加单词组成,直到它太大,然后擦除最后一个单词并插入或附加空格。

这是很多不必要的复制和修改。

有些可以通过首先计算所需的空格,然后处理适合右偏移量行的单词来保存。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
// Helper function which copies the elements of a range into a destination object
// spaced by the result of a given function. The destination must be big enough.
template< class InputIt, class Dest, class Func >
void copy_spaced( InputIt first, InputIt last
, Dest& dest
, Func offset )
{
auto src = first;
auto it = std::copy(src->cbegin(), src->cend(), dest.begin());
while ( ++src != last )
{
it = std::copy( src->cbegin(), src->cend()
, it + offset(std::distance(first, src)) );
}
}
// As stated, the input is a vector of single words and a width
auto justify_lines( std::vector<std::string> const& words
, size_t width )
{
std::vector<std::string> result;
auto first = words.cbegin();
auto it = first;
// Accumulate the number of chars in the words.
size_t count{};
// Minimum number of spaces between each word.
size_t min_spaces{};
while ( it != words.cend() )
{
// Check if the current word can be added to the current line
if ( count + it->size() + min_spaces > width )
{
if ( it->size() > width ) {
std::cerr << "This word is too big: " << *it << 'n';
return result;
}
// Copy the words only when the line is full. Start by adding an "empty"
// line to the vector of justified lines.
result.emplace_back(width, ' ');
size_t n_spaces = width - count;
size_t n_words = std::distance(first, it);
// A single word is left justified.
if ( n_words <= 1 )
{
std::copy(first->cbegin(), first->cend(), result.back().begin());
}
else
{
// Otherwise the strategy is to spread the spaces as evenly as possible.
size_t n_intervals = n_words - 1;
auto calc_offset = [ offset = n_spaces / n_intervals
, limit = n_spaces % n_intervals ] (size_t i) {
return i <= limit ? offset + 1 : offset;
};
copy_spaced(first, it, result.back(), calc_offset);
}
// We need to reset the counters, but the current word shouldn't be skipped.
min_spaces = 0;
count = it->size();
first = it++;
}
else {
count += it->size();
++min_spaces;
++it;
}
}
// The last line is justified to the left.
if ( first != it )
{
result.emplace_back(width, ' ');
copy_spaced(first, it, result.back(), []([[maybe_unused]]size_t i){ return 1; });
}
return result;
}

测试。