A firm gave me a small take home assignment which asks you to implement text formatter. Given some text which only contains alphanumerics and spaces (only one space between words), we should align it either using one of LEFT, RIGHT or CENTER. Here's the main logic
This is the header file
#pragma once
#include <string>
#include "utils.hpp"
namespace formatter
{
enum Align {
LEFT_ALIGN,
RIGHT_ALIGN,
CENTER_ALIGN
};
struct FormattedLine {
size_t start_index;
size_t end_index;
size_t left_padding;
size_t right_padding;
};
class Formatter {
public:
std::string AlignText(const std::string& text, size_t column_width, const std::string& align_mode);
Align GetAlignMode(const std::string& align_mode);
};
} // namespace formatter
And here's the main logic
#include <vector>
#include <iostream>
#include "formatter.hpp"
namespace formatter
{
Align Formatter::GetAlignMode(const std::string& align_mode) {
if (align_mode == "LEFT_ALIGN") {
return Align::LEFT_ALIGN;
} else if (align_mode == "RIGHT_ALIGN") {
return Align::RIGHT_ALIGN;
} else if (align_mode == "CENTER_ALIGN") {
return Align::CENTER_ALIGN;
} else {
throw std::invalid_argument("Align mode \"" + align_mode + "\" is not currently supported");
}
}
std::string Formatter::AlignText(const std::string& text, size_t column_width, const std::string& align_mode) {
if (!formatter_utils::IsValid(text)) {
std::cerr << "Error: Invalid text input. No characters apart from lowercase ASCII or uppercase ASCII or spaces is allowed" << std::endl;
return "";
}
if (!text.length()) {
std::cerr << "Error: Empty input" << std::endl;
return "";
}
std::vector<std::string> words = formatter_utils::SplitString(text);
std::vector<FormattedLine> lines;
auto const construct = [this, &lines, &column_width, &align_mode](size_t start_index, size_t end_index, size_t current_line_length) {
switch (GetAlignMode(align_mode)) {
case Align::LEFT_ALIGN:
{
lines.emplace_back(FormattedLine{start_index, end_index, 0, 0});
break;
};
case Align::RIGHT_ALIGN:
{
auto padding_length = std::max(0ul, column_width - current_line_length + 1);
lines.emplace_back(FormattedLine{start_index, end_index, padding_length, 0});
break;
};
case Align::CENTER_ALIGN:
{
auto padding_length = std::max(0ul, column_width - current_line_length + 1);
// For uneven padding length, Keep the text more left aligned than right aligned
auto left_padding_length = padding_length / 2;
auto right_padding_length = padding_length - left_padding_length;
lines.emplace_back(FormattedLine{start_index, end_index, left_padding_length, right_padding_length});
};
}
};
size_t start_index = 0, current_line_length = 0;
for (size_t end_index = 0; end_index < words.size(); end_index++) {
const auto& word = words[end_index];
// If the word is longer than column width, print error to STDERR
if (word.length() > column_width) {
std::cerr << "Error: current word \"" << word << "\" is longer than column width (" << column_width << ")" << std::endl;
return "";
}
if (current_line_length + word.length() > column_width) {
construct(start_index, end_index, current_line_length);
current_line_length = word.length() + 1;
start_index = end_index;
}
else {
current_line_length += word.length() + 1;
}
}
if (current_line_length) {
construct(start_index, words.size(), current_line_length);
}
std::string result;
// This looks like O(N^2) but we are just iterating through all words using their respective indices
for (const auto& [start_index, end_index, left_padding, right_padding] : lines) {
result += std::string(left_padding, ' ');
for (auto index = start_index; index < end_index; index++) {
result += words[index];
result += ' ';
}
result.pop_back();
result += std::string(right_padding, ' ');
result += "\n";
}
result.pop_back();
return result;
}
} // namespace formatter
The time complexity for this solution is \$O(N)\$ where \$N\$ is the length of the text and Space would be \$O(N) + O(L)\$ where \$L\$ is the number of formatted lines. I thought the solution was optimal enough but apparently the firm thinks that this is an okay solution.
I was wondering what could I have done in order to optimise this. One thing I can think of is that iterate through given text without breaking them into words which get rids of additional space but time complexity would still be same. Wondering if community can provide more feedback on this
Note: Ignore the errors being printed out to STDERR. That's a requirement otherwise, I would never do that