Minimum Absolute Distance
Headers and namespace

We're missing headers

#include &lt;algorithm&gt;
#include &lt;climits&gt;
#include &lt;cmath&gt;
#include &lt;vector&gt;


Also, it appears the code assumes using namespace std.  Bringing all names in from a namespace is problematic; namespace std particularly so. See Why is “using namespace std” considered bad practice?.

Code the solution, and adapt it to fit

The use of the Solution class appears to be an artefact of your test environment.  Since the function doesn't need any state, prefer to write it as you normally would:

// we'll change this signature later
static int minimum_range(const std::vector&lt;int&gt; &amp;A,
                         const std::vector&lt;int&gt; &amp;B,
                         const std::vector&lt;int&gt; &amp;C);


And then provide Solution as a thin wrapper around it, like:

int Solution::solve(std::vector&lt;int&gt; &amp;A, std::vector&lt;int&gt; &amp;B, std::vector&lt;int&gt; &amp;C) {
    return minimum_range(a, b, c);
}


We can then call minimum_range from our test program much more simply:

int main()
{
    return
        + (0 != minimum_range(std::vector{5}))
        // add more tests here
        + (1 != minimum_range(std::vector{1, 4, 5, 8, 10}, std::vector{6, 9, 15}, std::vector{2, 3, 6, 6}));
}


We might make an exception to this general advice in the case of competitive performance-oriented programming; but then code review goes out of the window entirely, as speed trumps style and maintainability there.

Algorithm

The method is basically sound; it scales well to large vectors, but doesn't scale well to many vectors (as you note in the description).

For general code, prefer to think in iterators rather than indexes.  The code will be equivalent, but usable with more types than just vectors and arrays.

If we keep a collection of iterators (one for each of the arrays), then at each step, we want to advance the one that points to the smallest element (added complication - we need to tie-break by choosing the one that advances the least).  We have finished when that one reaches the end of its array; that means we also need to remember the end iterator for each array.  That means we end up storing a range for each input vector.

template&lt;typename Iter&gt;
struct range
{
    Iter current;
    Iter const end;
};

template&lt;typename T&gt;
range&lt;typename std::vector&lt;T&gt;::const_iterator&gt; make_range(const std::vector&lt;T&gt; &amp;v)
{
    return {v.begin(), v.end()};
}


Now we can transform the vectors into ranges:

static int minimum_range(const std::vector&lt;int&gt; &amp;A,
                         const std::vector&lt;int&gt; &amp;B,
                         const std::vector&lt;int&gt; &amp;C)
{
    auto range = { make_range(A), make_range(B), make_range(C) };

    auto minmax_range = std::minmax_element(range.begin(), range.end());


For the std::minmax_element() call to work, we'll need a suitable &lt; operator in our range.  Add this:

bool operator&lt;(const range&amp; other) const
{
    if (current == end) return false;
    if (other.current == other.end) return true;
    auto a = *current, b = *other.current;
    if (a != b) return a &lt; b;

    // it's a draw - which one advances least?
    if (current+1 == end) return false;
    if (other.current+1 == other.end) return true;
    a = current[1], b = other.current[1];
    return a &lt; b;
}


Now let's go back to the algorithm and make it iterate:

auto minmax_range = std::minmax_element(r.begin(), r.end());
auto&amp; min_range = minmax_range.first;
auto&amp; max_range = minmax_range.second;
int best = **max_range - **min_range;

while ((++*min_range).current != min_range-&gt;end) {
    minmax_range = std::minmax_element(r.begin(), r.end());
    best = std::min(best, **max_range - **min_range);
    if (best == 0) {
        break;   // we can't improve on zero
    }
}


There's some stuff to explain there.  We create aliases for the minmax_range, which is a pair of iterators to range objects.  We use the dereference operator, which needs defining in range to give the current first element of the range:

auto operator*() const { return *current; }


The loop control starts by incrementing the lowest range - that needs an implementation:

range&amp; operator++() { ++current; return *this; }


If that produced a range that has reached the end, then we've considered all the possibilities.

Inside the loop, we find the new min and max (remember that min_range and max_range still alias the members of minmax_range), and update best if required.

Extension to many inputs

We can now use a std::initializer_list to supply an arbitrary number of collections of any kind of (comparable) element.  I'll use C++17 for this (so we can write an implicit constructor for range, using a deduction guide).

#include &lt;algorithm&gt;
#include &lt;vector&gt;

template&lt;typename Iter&gt;
struct range
{
    Iter current;
    Iter const end;

    template&lt;typename T&gt;
    range(const T&amp; v)
        : current{v.begin()},
          end{v.end()}
    {
    }

    explicit operator bool() const { return current != end; }

    auto operator*() const { return *current; }

    range&amp; operator++() { ++current; return *this; }

    bool operator&lt;(const range&amp; other) const
    {
        return *this &amp;&amp; (!other || *current &lt; *other.current);
    }
};

// deduction guide
template&lt;typename Container&gt;
range(Container c) -&gt; range&lt;typename Container::const_iterator&gt;;


template&lt;typename Iter&gt;
static auto minimum_range(std::initializer_list&lt;range&lt;Iter&gt;&gt; containers)
{
    using std::begin;
    using std::end;

    // Copy initializer list to read/write container
    std::vector r(begin(containers), end(containers));

    auto minmax_range = std::minmax_element(begin(r), end(r));
    auto&amp; min_range = minmax_range.first;
    auto&amp; max_range = minmax_range.second;
    auto best = **max_range - **min_range;

    while (++*min_range) {
        minmax_range = std::minmax_element(begin(r), end(r));
        best = std::min(best, **max_range - **min_range);
    }

    return best;
}

// convert containers to ranges and forward
template&lt;typename... Args&gt;
static auto minimum_range(const Args&amp;... args)
{
    return minimum_range({range(args)...});
}




#include &lt;list&gt;
int main()
{
    return
        + (0 != minimum_range(std::list{5}))
        + (0.5 != minimum_range(std::vector{0.0}, std::vector{0.0}, std::vector{0.5}))
        + (6 != minimum_range(std::vector{6,30}, std::vector{10,12}, std::vector{6,15,30}, std::vector{12}))
        + (1 != minimum_range(std::vector{0, 6, 10}, std::vector{5}, std::vector{5}))
        // add more tests here
        + (1 != minimum_range(std::list{1, 4, 5, 8, 10}, std::list{6, 9, 15}, std::list{2, 3, 6, 6}));
}


I was unable to construct a test that proves the need for the tie-break in operator&lt;, so I removed that code.  I shouldn't have written it in the first place without a test to exercise it, of course...