Find Sum Pairs

/**
* Design an algorithm to find all pairs of integers within an array which
* sum to a specified value.
*/

/*
First some assumptions:
- I am going to assume that the same point cannot be used twice.
  For example, if I have {1}, and my target is 2. Then I cannot have {1,1}
- Secondly, I am going to assume a number can used more than once. For
  example: if I have {1,9,9,1} and my target is 10, then I can have both
  {1, 9}, {9, 1}, {9, 1}, and {1, 9} (iterating left through right). So
  if there is at least one number in the pair, then it is valid, and every
  pair contains at least 1 unused element in the array.
- Duplicate pairs are allow, as so long as they follow the previous condition.

The Algorithm:
- Compile a hash table of the number and its frequency. Hash through with 
  target - data[i] to find a valid sum.
- If the data is the same as the difference, the frequency must be > 1
  in order for the first assumption to make sense.
*/

vector<pair<int, int>> sum_pairs(vector<int> &data, int target)
{
    vector<pair<int, int>> valid_pairs;
    unordered_map<int, int> num_freq;

    for (auto i : data) {
        if (num_freq.find(i) == num_freq.end()) {
            num_freq.insert({i, 1});
        }
        else num_freq[i]++;
    }

    for (int i = 0; i < data.size(); i++) {

        int look_for = target - data[i];
        auto found = num_freq.find(look_for);

        if (found != num_freq.end()) { // found
            if (look_for == data[i]
                && found->second > 1) { // duplicate
                valid_pairs.push_back({data[i], look_for});
            }
            else if (look_for != data[i]){
                valid_pairs.push_back({ data[i], look_for });
            }
        }
    }

    return valid_pairs;
}

/*
This next implementation is going constrain a few more assumptions:
- First assumption from above.
- No duplicate pairs

The Algorithm:
- Essentially the same as above, but we contain an additional container that
  will contain the unique pairs. So before confirming an insertion for a valid
  pair, we hash to the location of the pair and confirm whether it exists or not.

*/

struct pair_hash
{
    inline size_t operator()(const pair<int, int> &p) const {
        hash<int> int_hasher;
        return int_hasher(p.first) ^ int_hasher(p.second);
    }
};

vector<pair<int, int>> sum_pairs2(vector<int> &data, int target)
{
    vector<pair<int, int>> valid_pairs;
    unordered_map<int, int> num_freq;
    unordered_set<pair<int, int>, pair_hash> unique_pairs;

    for (auto i : data) {
        if (num_freq.find(i) == num_freq.end()) {
            num_freq.insert({ i, 1 });
        }
        else num_freq[i]++;
    }

    for (int i = 0; i < data.size(); i++) {

        int look_for = target - data[i];
        auto found = num_freq.find(look_for);
        bool is_unique = unique_pairs.find({ data[i], look_for })
                       == unique_pairs.end();

        if (found != num_freq.end() && is_unique){ // found and unique
            if (look_for == data[i]
                && found->second > 1) { // duplicate
                valid_pairs.push_back({ data[i], look_for });
                unique_pairs.insert({ data[i], look_for });
            }
            else if (look_for != data[i]) {
                valid_pairs.push_back({ data[i], look_for });
                unique_pairs.insert({ data[i], look_for });
            }
        }
    }

    return valid_pairs;
}

void print_pairs(vector<pair<int, int>> &pairs)
{
    for (auto i : pairs) {
        cout << i.first << "," << i.second << endl;
    }
}

int main()
{
    vector<int> data = { 1,2,11,1,1,1,1,2,23,34,43,232,122,-20,30,2,3,4,7,9 };
    vector<pair<int, int>> valid_pairs = sum_pairs(data, 10);
    print_pairs(valid_pairs);
    cout << endl;

    vector<pair<int, int>> valid_pairs2 = sum_pairs2(data, 10);
    print_pairs(valid_pairs2);

}

Last updated