Lexicographically largest string from allowed swaps Problem: Given a string str and array of pairs that indicates which
  indices in the string can be swapped, return the lexicographically
  largest string that results from doing the allowed swaps. You can swap
  indices any number of times.
  
  Example
  
  For str = "abdc" and pairs = [[1, 4], [3, 4]], the output should be
  swapLexOrder(str, pairs) = "dbca".
  
  By swapping the given indices, you get the strings: "cbda", "cbad",
  "dbac", "dbca". The lexicographically largest string in this list is
  "dbca".


My comments: My program passed all the tests on the CodeSignal website, but since I am relatively new to algorithms, there's probably a more efficient way to solve it. In addition, I'm looking for general code review: does my code have signs that I look like a beginner? thank you.

#include&lt;iostream&gt;
#include&lt;set&gt;
#include&lt;string&gt;
#include&lt;vector&gt;
#include&lt;map&gt;
#include&lt;algorithm&gt;

std::string swapLexOrder(std::string str, std::vector&lt;std::vector&lt;int&gt;&gt; pairs)
{
    if(pairs.size() == 0) return str;
    std::vector&lt;std::set&lt;int&gt;&gt; pairpool; //pairpool : contains sets of interchangeable indices
    std::vector&lt;std::vector&lt;std::string&gt;&gt; stringpool; //stringpool : contains vectors of interchangeable characters

    //creates pairpool structure
    for(std::size_t i = 0; i &lt; pairs.size(); i++)
    {
        bool alrExists = false;
        std::set&lt;int&gt; newSet;
        for(auto&amp; p : pairpool)
        {
            for(auto ele : p)
            {
                if((pairs[i][0] == ele) || (pairs[i][1] == ele))
                {
                    if(!alrExists)
                    {
                        alrExists = true;
                        p.insert(pairs[i][0]);
                        p.insert(pairs[i][1]);
                        newSet = p;
                    }
                    else
                    {
                        if(p == newSet) break;
                        p.insert(newSet.begin(), newSet.end());
                        pairpool.erase(std::remove(pairpool.begin(), pairpool.end(), newSet), pairpool.end());
                        break;  //  needed this break statement really badly
                    }
                }
            }
        }
        if(!alrExists)
        {
            newSet.insert(pairs[i][0]);
            newSet.insert(pairs[i][1]);
            pairpool.push_back(newSet);
        }
    }

    //creates sorted stringpool structure
    for(auto p : pairpool)
    {
        std::vector&lt;std::string&gt; newset;
        for(auto ele : p)
        {
            newset.push_back(str.substr(ele - 1, 1));
        }
        std::sort(newset.begin(), newset.end());
        stringpool.push_back(newset);
    }

    //uses stringpool and pairpool to modify string only one time through
    int counter = 0;
    for(auto p : pairpool)
    {
        for(auto ele : p)
        {
            str.replace(ele - 1, 1, stringpool[counter].back());
            stringpool[counter].pop_back();
        }
        counter++;
    }

    return str;
}

int main()
{
    std::cout &lt;&lt; swapLexOrder("acxrabdz", {{1, 3}, {6, 8}, {3, 8}, {2, 7}}) &lt;&lt; "\n";
    std::string STR = "lvvyfrbhgiyexoirhunnuejzhesylojwbyatfkrv";
    std::vector&lt;std::vector&lt;int&gt;&gt; PAIR =
    {
        {13, 23},
        {13, 28},
        {15, 20},
        {24, 29},
        {6, 7},
        {3, 4},
        {21, 30},
        {2, 13},
        {12, 15},
        {19, 23},
        {10, 19},
        {13, 14},
        {6, 16},
        {17, 25},
        {6, 21},
        {17, 26},
        {5, 6},
        {12, 24}
    };
    std::cout &lt;&lt; swapLexOrder(STR, PAIR) &lt;&lt; "\n";
    return 0;
}
Your code is quite good for a beginning, but there's still much room for improvement. Your code main flaw is that it is difficult to read. There are also some performance issues, but they are a lot easier to correct.
N.B: I'll stay close to your algorithm, although you could probably find a better one in a graph library (see for instance https://en.wikipedia.org/wiki/Connected_component_(graph_theory)#algorithms)
Performance
You must pick your types more carefully. Don't choose a type that allocates memory when you can use one that doesn't. For instance, don't represent a pair of indices by a std::vector: a pair will always have two elements, there is no need to ever grow it. So choose a std::pair&lt;int, int&gt; instead: it is lighter, quicker, and reflects your intent more clearly. In the same way, don't use std::string to represent 1 character: your stringpool can as well be of type std::vector&lt;std::string&gt;.
You must also be more careful while passing objects around. Don't pass large objects by value unless you need both to copy and modify them. For instance, the signature: std::string swapLexOrder(std::string str, std::vector&lt;std::vector&lt;int&gt;&gt; pairs) is only partially correct. You will indeed modify str, and you want the user to keep his original string untouched, so passing by value is a good call. But pairs is read-only in your code, so pass it by const reference.
Expressiveness
Your code is one big function containing a lot of nested loops. As a result,it's very hard to understand, let alone optimize. There is two ways to fix it: the first is to better comment on your algorithm (for instance, a minimum would be: first, we merge all pairs of indices that are connected together; then we extract the corresponding characters from the input string, sort them in decreasing order and put them back); the second, is to make your code express your intent clearly.
The most important rule, which also is one of the hardest to obey, is to choose meaningful names. newset doesn't mean much, neither does p. pairpool should not contain set of more than two elements.
Another way to write more expressive code is to avoid &quot;raw loops&quot;. Use named algorithms instead. For instance, I rewrote the first part of your algorithm as a combination of a partition discriminating sets containing one element of the considered pair and an accumulation which merges them:
std::string swapLexOrder(std::string str, const std::vector&lt;std::pair&lt;int, int&gt;&gt;&amp; pairs)
{
    if(pairs.size() == 0) return str;
    std::vector&lt;std::set&lt;int&gt;&gt; index_permutations; //pairpool : contains sets of interchangeable indices
    
    for(auto pair : pairs)
    {   
        // [matches, end) &lt;- sets containing either one of the pair's elements   
        auto matches = std::partition(index_permutations.begin(), index_permutations.end(), 
                                      [&amp;pair](const auto&amp; permutation_set) {
            return std::none_of(permutation_set.begin(), permutation_set.end(), [&amp;pair](auto index) {
                return index == pair.first || index == pair.second;
            });
        });
        
        if (matches == index_permutations.end()) index_permutations.push_back({pair.first, pair.second});
        else { // merge matches
            *matches = std::accumulate(matches, index_permutations.end(),
                                       std::set&lt;int&gt;{pair.first, pair.second},
                                       [](auto&amp;&amp; init, auto&amp;&amp; permutation) {
                init.insert(permutation.begin(), permutation.end());
                return init;
            });
            index_permutations.erase(std::next(matches), index_permutations.end());
        }
    }
// ...

Here's a link to the partially rewritten code if you want to experiment with it: https://wandbox.org/permlink/6Wij6Y4NuooMlW6C