Very good. Please try and continue to learn about memoization.
I will give an additional method. You can also "memoize" values in a DP table. DP like dynamic programming.
If you go for speed and can afford a big memory consumption, then this is the fastest and most efficient solution. Using recursion for that sequence is basically a bad idea and will result in very slow code and potential stack overflows.
Converting the recursive into an iterative solution with memoization in a DP table, will give you a very fast result. Even for big numbers. With compiler optimizations on, you can calculate the complete sequence for example up to 100000 ultrafast.
See the below:
#include <iostream>
#include <array>
#include <cstdint>
// We will calculate a Golomb sequence up to the below specified element
constexpr size_t MaxValues = 100000;
using MyDataType = uint_fast16_t;
using GolombSequence = std::array<MyDataType, MaxValues>;
// This is the Golomb Sequence
GolombSequence golombSequence{};
// Iterative Function to calculate a Golomb sequence using a DP table
void createGolombSequence() {
golombSequence[1] = 1;
for (int i = 2; i < MaxValues; ++i) {
golombSequence[i] = 1 + golombSequence[i - golombSequence[golombSequence[i - 1]]];
}
}
// Test
int main() {
createGolombSequence();
std::cout << golombSequence[777] << '\n';
std::cout << golombSequence[7777] << '\n';
std::cout << golombSequence[77777] << '\n';
}
We can even go one step ahead and use "compile time memoization", meaning, we will calculate the complete sequence at compile time. So, let the compiler do the work.
This will of course result in the fastest possible solution with the downside of high memory consumption and a little bit limited by the cababilities of the compiler.
Please see below. All Golomb value calculation is done at compile time. At runtime, we just use an ultrafast indexing operation:
#include <iostream>
#include <array>
#include <cstdint>
// We will calculate a Golomb sequence up to the below specified element
constexpr size_t MaxValues = 100000u;
using MyDataType = uint_fast16_t;
using GolombSequence = std::array<MyDataType, MaxValues>;
// Iterative Function to calculate a Golomb sequence using a DP table
constexpr GolombSequence createGolombSequence() {
GolombSequence golombSequence{};
golombSequence[1] = 1;
for (int i = 2; i < MaxValues; ++i) {
golombSequence[i] = 1 + golombSequence[i - golombSequence[golombSequence[i - 1]]];
}
return golombSequence;
}
// This is the Golomb Sequence
constexpr GolombSequence golombSequence = createGolombSequence();
// Test
int main() {
std::cout << golombSequence[777] << '\n';
std::cout << golombSequence[7777] << '\n';
std::cout << golombSequence[77777] << '\n';
}
I added my code to Franks Benchmark. The result is dramatically outperforming everything else. The green line at 0ms is for the above algorithm.

Used benchmark code
#include <chrono>
#include <iostream>
#include <array>
#include <cstdint>
// We will calculate a Golomb sequence up to the below specified element
constexpr size_t MaxValues = 10000u;
using MyDataType = uint_fast16_t;
using GolombSequence = std::array<MyDataType, MaxValues>;
// Iterative Function to calculate a Golomb sequence using a DP table
constexpr GolombSequence createGolombSequence() {
GolombSequence golombSequence{};
golombSequence[1] = 1;
for (int i = 2; i < MaxValues; ++i) {
golombSequence[i] = 1 + golombSequence[i - golombSequence[golombSequence[i - 1]]];
}
return golombSequence;
}
// This is the Golomb Sequence
constexpr GolombSequence golombSequence = createGolombSequence();
inline int golombFast(size_t i) { return golombSequence[i]; };
int golom(int n)
{
if (n == 1) {return 1;}
return 1 + golom(n - golom(golom(n - 1)));
}
int golomS(int n, std::unordered_map<int, int>& golomb)
{
if(n == 1)
{
return 1;
}
if(!golomb[n])
{
golomb[n] = 1 + golomS(n - golomS(golomS(n - 1, golomb), golomb), golomb);
}
return golomb[n];
}
static void TestGolombFast(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(golombFast(state.range(0)));
}
}
BENCHMARK(TestGolombFast)->DenseRange(1, 17, 2);
static void TestGolomb(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(golom(state.range(0)));
}
}
BENCHMARK(TestGolomb)->DenseRange(1, 17, 2);
static void TestGolombS(benchmark::State& state) {
for (auto _ : state) {
std::unordered_map<int, int> golomb;
// Be extra-generous, ignore construction and destruction of the set
auto start = std::chrono::high_resolution_clock::now();
benchmark::DoNotOptimize(golomS(state.range(0), golomb));
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(
end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
BENCHMARK(TestGolombS)->DenseRange(1, 17, 2);