recursionreferencesubset

Why does passing by reference change the answer while producing unique subsets?


Here is a solution to a problem to generate unique subsets of an array nums:

#include <bits/stdc++.h>
using namespace std;
void solveRec(vector<int> ss, set<vector<int>> &ans, vector<int> &nums, int i)
{
    if (i == nums.size())
    {
        sort(ss.begin(), ss.end());
        ans.insert(ss);
        return;
    }

    ss.push_back(nums[i]);
    solveRec(ss, ans, nums, i + 1);
    ss.pop_back();

    solveRec(ss, ans, nums, i + 1);
}

This function takes an integer array nums as input along with a set of vectors ans to store unique subsets. While passing the vector ss for storing current subset by value produces the correct answer, passing it by reference does not, why could this be?

let nums be 4 4 4 1

passing by reference (incorrect) produces:

1 
1 1 
1 1 4 
1 4 
1 4 4 
1 4 4 4

passing by value (correct) produces:

1 
1 4 
1 4 4 
1 4 4 4 
4 
4 4 
4 4 4

Please help!!!


Solution

  • When ss is passed by reference, all mutations that happen to ss are to a single vector instance, which is shared by all execution contexts of the function solveRec. As a consequence, sort(ss.begin(), ss.end()); has no "local" effect. The negative effects of this kick in when ss.pop_back(); is executed. The intention of this instruction is to remove the same value that was added to ss with the ss.push_back(nums[i]) call that appears two lines earlier. But this is no longer guaranteed, because in the mean time that ss has been sorted, and so the popped element might be a different value.

    With the call-by-value version of the code, the sort call has an effect only on the local copy of ss, and not to the ss of the caller.

    If you leave out the sort call, it will work also with the pass-by-reference version, but then obviously the generated subsets will not be sorted. You could do that afterwards.