Paul wrote:
> On Saturday, October 20, 2018 at 7:54:06 AM UTC+1, Pavel wrote:
...
>
>
> Very interesting thoughts. Any ideas for references to implement some of
> these more advanced ideas? I'm googling the template design method and
> everything else in your post to try to create a better solutions to learn
> from this interview, and I think I would do much better with more
> concrete guidance.
Please see below. I implemented the more efficient solution I referred to.
Admittedly, it is difficult to go all the way to this solution during the
interview; but it is still possible to keep moving in the right direction by
incremental improvements: the interviewee will either gain himself/herself more
time to finish the problem or the interviewer moves on to another problem when
it is obvious for for them the interviewee knows what s/he is doing and will
finish the job eventually.
It is sometimes difficult to write a generic template method like RunDumbRle
below correctly off the bat. I usually write at least 2 instances and make them
as similar as possible after which the correct line between generic and specific
behaviors usually becomes more clear. As an illustration, I left the two
original concrete functions in the comments below the code.
HTH,
-Pavel
> Many thanks,
>
> Paul
>
// ------------ cut here ---------
#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef string::size_type Size;
Size
CalcEncodedCounterSize(Size counter)
{
for (Size result = 1; ; ++result)
if ((counter /= 10) == 0)
return result;
}
vector<Size>
CalcEncodedCounterSizeLimits(Size maxSize)
{
const Size MaxEncodedSize = CalcEncodedCounterSize(maxSize);
vector<Size> result;
result.push_back(9);
for (vector<Size>::size_type nNines = 2; nNines < MaxEncodedSize; ++nNines)
result.push_back(result.back() * 10 + 9);
return result;
}
Size
GetEncodedCounterSize(Size counter)
{
static const Size MaxCounter = string().max_size();
assert(counter <= MaxCounter);
static const vector<Size> EncodedCounterSizeLimits(
CalcEncodedCounterSizeLimits(MaxCounter));
const vector<Size>::size_type nLimits = EncodedCounterSizeLimits.size();
for (vector<Size>::size_type i = 0; i < nLimits; ++i) {
if (counter <= EncodedCounterSizeLimits[i])
return i + 1;
}
return nLimits;
}
void
EncodeCounterToString(string& result, Size counter)
{
const static char Digits[] = "0123456789";
Size fromIndex = result.size();
do {
result += Digits[counter % 10];
counter /= 10;
} while (!!counter);
reverse(result.begin() + fromIndex, result.end());
}
template<typename R/*result type*/, typename I/*result initializer*/,
typename U/*result updater*/>
R
RunDumbRle(const string& str, I initFunc, U updateFunc)
{
assert(!str.empty());
R result(initFunc());
char prevChar = str[0];
const Size strLen = str.size();
if (strLen == 1) {
updateFunc(result, 1, prevChar);
return result;
}
Size counter = 1;
for (Size i = 1; ; ++i) {
if (i == strLen) {
updateFunc(result, counter, prevChar);
break;
}
const char curChar = str[i];
if (curChar == prevChar) {
++counter;
continue;
}
updateFunc(result, counter, prevChar);
prevChar = curChar;
counter = 1;
}
return result;
}
string
DumbRleEncode(const string& str)
{
if (str.empty())
return str;
const Size resultSize = RunDumbRle<Size>(str,
[]{return 0;},
[](Size& result, Size counter, char){
result += GetEncodedCounterSize(counter) + 1;
});
return RunDumbRle<string>(str,
[&resultSize](){
string result;
result.reserve(resultSize);
return result;
},
[](string& result, Size counter, char c) {
result += c;
EncodeCounterToString(result, counter);
});
}
int
main(int, char*[])
{
assert(CalcEncodedCounterSize(1) == 1);
assert(GetEncodedCounterSize(1) == 1);
assert(DumbRleEncode("") == "");
assert(DumbRleEncode("a") == "a1");
assert(DumbRleEncode("ab") == "a1b1");
assert(DumbRleEncode("abc") == "a1b1c1");
assert(DumbRleEncode("abbbbbbc") == "a1b6c1");
assert(DumbRleEncode("aaaaaaaaaac") == "a10c1");
assert(DumbRleEncode(string(1000, 'b')) == "b1000");
return 0;
}
/*
string
DumbRleEncodeOrig(const string& str)
{
if (str.empty())
return string();
string result;
result.reserve(CalcDumbRleEncodedSize(str));
char prevChar = str[0];
const Size strLen = str.size();
if (strLen == 1) {
result += prevChar;
EncodeCounterToString(result, 1);
return result;
}
Size counter = 1;
for (Size i = 1; ; ++i) {
if (i == strLen) {
result += prevChar;
EncodeCounterToString(result, counter);
break;
}
const char curChar = str[i];
if (curChar == prevChar) {
++counter;
continue;
}
result += prevChar;
EncodeCounterToString(result, counter);
prevChar = curChar;
counter = 1;
}
return result;
}
Size
CalcDumbRleEncodedSize(const string& str)
{
assert(!str.empty());
Size result = 0;
char prevChar = str[0];
Size counter = 1;
const Size strLen = str.size();
for (Size i = 1; ; ++i) {
if (i == strLen) {
result += GetEncodedCounterSize(counter) + 1;
break;
}
const char curChar = str[i];
if (curChar == prevChar) {
++counter;
continue;
}
result += GetEncodedCounterSize(counter) + 1;
prevChar = curChar;
counter = 1;
}
return result;
}
*/