SyntaxFlow
Maximum Sum Combination Using Heap (Priority Queue) in C++ | Top K Pair Sums Explained
Data Structures and algorithms

Maximum Sum Combination Using Heap (Priority Queue) in C++ | Top K Pair Sums Explained

CH
chakradhar·
Learn how to solve the Maximum Sum Combination problem using a Max Heap and Priority Queue in C++. Includes intuition, algorithm, dry run, optimized code, and complexity analysis.
#Walmart#Epam

1. Problem Statement

In Simple Words: Imagine you have two separate decks of cards with numbers on them. You draw one card from the first deck and one card from the second deck, adding their values together to get a "sum combination." Your task is to find the highest possible sums you can make, specifically the top CC highest sums, in decreasing order.

Original Problem Statement:

Given two integer arrays AA and BB of size NN each, and an integer CC, find the top CC maximum sum combinations where a combination is defined as A[i]+B[j]A[i] + B[j]. Return the sums in descending order.

Input Format:

  • An integer array AA of size NN.
  • An integer array BB of size NN.
  • An integer CC representing the number of top sums required.

Output Format:

  • An integer array of size CC containing the top CC maximum sum combinations.

Constraints:

  • 1N1051 \le N \le 10^5
  • 1C1051 \le C \le 10^5
  • 1A[i],B[i]1051 \le A[i], B[i] \le 10^5

2. Examples

Let's look at a few examples to understand how the combinations work.

Example 1

Input: A = [3, 2], B = [1, 4], C = 2

Output: [7, 6]

Step-by-Step Explanation:

  1. Let's generate all possible combinations A[i]+B[j]A[i] + B[j]:
    • 3 + 1 = 4
    • 3 + 4 = 7
    • 2 + 1 = 3
    • 2 + 4 = 6
  2. The complete list of sums is [4, 7, 3, 6].
  3. Sorting them in descending order gives [7, 6, 4, 3].
  4. We only need the top C=2C = 2 sums, which are 7 and 6.

Example 2

Input: A = [1, 4, 2, 3], B = [2, 5, 1, 6], C = 4

Output: [10, 9, 9, 8]

Step-by-Step Explanation:

  1. If we take the highest from AA (which is 4) and highest from BB (which is 6), the sum is 10.
  2. The next highest could be 4 (from AA) + 5 (from BB) = 9.
  3. Another high combination is 3 (from AA) + 6 (from BB) = 9.
  4. The next highest is 4 (from AA) + 4 (Wait, 4 is not in BB. The next valid combinations are 3+5=8 or 2+6=8).
  5. The top 4 sums are 10, 9, 9, and 8.

3. Key Observations

Before jumping into solutions, here are the hidden truths of the problem:

  • Sorting Creates Predictability: In an unsorted array, the maximum sum could be anywhere. If you sort both arrays in descending order, the absolute highest sum is guaranteed to be A[0]+B[0]A[0] + B[0].
  • The "Next Best" Candidates: Once you use A[0]+B[0]A[0] + B[0], what is the next largest sum? It must be either A[1]+B[0]A[1] + B[0] or A[0]+B[1]A[0] + B[1]. There is no mathematical possibility for A[2]+B[2]A[2] + B[2] to be greater than those two.
  • Overlapping Paths: If you move from indices (0,0) to (1,0), and then to (1,1), you reach the same combination as moving from (0,0) to (0,1) and then to (1,1). We must avoid calculating and storing the same index pairs multiple times.

4. Intuition

Let's build the intuition using a visual matrix. Imagine we sort A=[4,3,2,1]A = [4, 3, 2, 1] and B=[6,5,2,1]B = [6, 5, 2, 1] in descending order. Now, imagine a 2D grid where the cell at row ii and column jj represents the sum A[i]+B[j]A[i] + B[j].

Grid visualisation

Notice how the values naturally decrease as you move right or down.

  • The absolute maximum is at the top-left corner (0,0).
  • If we take (0,0), the "frontier" of the next possible largest sums are its immediate right neighbor (0,1) and immediate bottom neighbor (1,0).
  • To constantly keep track of the largest available sum on this expanding frontier, we need a data structure that acts like a VIP line, always pushing the largest value to the front. This is the exact definition of a Max-Heap (Priority Queue)!

5. Brute Force Solution

Thought Process

If we don't know the priority queue approach, the simplest way is to physically generate every single possible pair, store their sums in a massive list, sort that list, and return the first CC elements.

Algorithm

  1. Create an empty list all_sums.
  2. Loop ii from 0 to N1N-1 for array AA.
  3. Inside, loop jj from 0 to N1N-1 for array BB.
  4. Calculate A[i]+B[j]A[i] + B[j] and append it to all_sums.
  5. Sort all_sums in descending order.
  6. Return the first CC elements.

C++ Implementation

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> maxCombinationsBrute(vector<int>& A, vector<int>& B, int C) {
    vector<int> all_sums;
    int n = A.size();
    
    // Generate all N^2 combinations
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            all_sums.push_back(A[i] + B[j]);
        }
    }
    
    // Sort in descending order
    sort(all_sums.begin(), all_sums.end(), greater<int>());
    
    // Extract top C
    vector<int> result;
    for (int i = 0; i < C; i++) {
        result.push_back(all_sums[i]);
    }
    
    return result;
}

Optimal Solution (Max-Heap + Visited Set)

We will use a Max-Heap to track the largest sums on our "frontier" and a Hash Set to ensure we don't evaluate the same (i, j) coordinate twice.

Search Space

Instead of searching N2N^2 elements, we only search up to CC elements. By popping the heap CC times, we guarantee we've found the top CC sums.

The Logic

  1. Sort both arrays in descending order. Now, A[0]A[0] and B[0]B[0] are the maximum elements.
  2. Initialize a Max-Heap. Each element in the heap will store the sum and its original indices: (sum, (i, j)).
  3. Initialize a Set to keep track of visited index pairs (i, j).
  4. Push the first, guaranteed largest pair (A[0] + B[0], (0, 0)) into the heap and mark (0, 0) as visited.
  5. Loop CC times:
    • Pop the top element from the heap. This is your current maximum sum. Add it to your result array.
    • From the indices (i, j) of the popped element, calculate its two neighbors in the conceptual matrix: (i + 1, j) and (i, j + 1).
    • For each neighbor, if it hasn't been visited and is within bounds, push it into the heap and mark it as visited.

8. Core Logic: The Expanding Frontier

Let's look at why the queue only needs (i+1, j) and (i, j+1).

When you extract the maximum element (0,0), the next logical maximums can only be exactly one step down or one step right in our grid visualization.

If we didn't use a visited set, the path (0,0) -> (1,0) -> (1,1) and the path (0,0) -> (0,1) -> (1,1) would result in the coordinates (1,1) being pushed into the Max-Heap twice. This would ruin our top CC count with duplicate instances of the same combination. The set acts as our gatekeeper.

9. Dry Run

Let's dry run the Max-Heap approach.

  • A=[1,4,2,3]A = [1, 4, 2, 3], B=[2,5,1,6]B = [2, 5, 1, 6], C=4C = 4.
  • Sort descending: A=[4,3,2,1]A = [4, 3, 2, 1], B=[6,5,2,1]B = [6, 5, 2, 1].

Initialization:

  • Max-Heap: [ (10, (0,0)) ] (Sum is 4+6=10)
  • Visited Set: {(0,0)}
  • Result: []

Iteration 1:

  • Pop (10, (0,0)). Result becomes [10].
  • Check neighbor (1,0): A[1]+B[0]=3+6=9A[1]+B[0] = 3+6 = 9. Not visited. Push (9, (1,0)). Add to Set.
  • Check neighbor (0,1): A[0]+B[1]=4+5=9A[0]+B[1] = 4+5 = 9. Not visited. Push (9, (0,1)). Add to Set.
  • Max-Heap now: [ (9, (1,0)), (9, (0,1)) ]

Iteration 2:

  • Heap top is (9, (1,0)) (or (0,1), tie doesn't matter). Let's pop (9, (1,0)). Result = [10, 9].
  • Check neighbor (2,0): A[2]+B[0]=2+6=8A[2]+B[0] = 2+6 = 8. Push (8, (2,0)). Add to Set.
  • Check neighbor (1,1): A[1]+B[1]=3+5=8A[1]+B[1] = 3+5 = 8. Push (8, (1,1)). Add to Set.
  • Max-Heap now: [ (9, (0,1)), (8, (2,0)), (8, (1,1)) ]

Iteration 3:

  • Pop (9, (0,1)). Result = [10, 9, 9].
  • Check neighbor (1,1): Already in Visited Set! Skip. (This proves why the set is crucial).
  • Check neighbor (0,2): A[0]+B[2]=4+2=6A[0]+B[2] = 4+2 = 6. Push (6, (0,2)). Add to Set.
  • Max-Heap now: [ (8, (2,0)), (8, (1,1)), (6, (0,2)) ]

Iteration 4 (Final since C=4C=4):

  • Top is (8, (2,0)) or (8, (1,1)). Pop one, say (8, (1,1)). Result = [10, 9, 9, 8].
  • Loop terminates.

Final Answer: [10, 9, 9, 8]. Exactly correct, without ever calculating the 1s1s and 2s2s.

10. Algorithm

  1. Sort arrays AA and BB in descending order.
  2. Create a Max-Heap that stores pairs in the format: pair<sum, pair<i, j>>.
  3. Create a set<pair<int, int>> to track visited indices (i, j).
  4. Push (A[0] + B[0], (0, 0)) into the heap and insert (0, 0) into the set.
  5. Create an output array result.
  6. Loop exactly CC times:
    • Pop the top element from the heap. Append its sum to result.
    • Extract its indices i and j.
    • If i + 1 < N and (i + 1, j) is not in the set:
      • Push (A[i+1] + B[j], (i+1, j)) into the heap.
      • Insert (i+1, j) into the set.
    • If j + 1 < N and (i, j + 1) is not in the set:
      • Push (A[i] + B[j+1], (i, j+1)) into the heap.
      • Insert (i, j+1) into the set.
  7. Return result.

11. C++ Code

Here is the clean, interview-ready implementation using standard C++ STL data structures:

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>

using namespace std;

vector<int> solve(vector<int> &A, vector<int> &B, int C) {
    int n = A.size();
    
    // Step 1: Sort both arrays in descending order
    sort(A.begin(), A.end(), greater<int>());
    sort(B.begin(), B.end(), greater<int>());
    
    // Max-Heap to store pairs of: (sum, (index_in_A, index_in_B))
    priority_queue<pair<int, pair<int, int>>> maxHeap;
    
    // Set to keep track of visited index pairs
    set<pair<int, int>> visited;
    
    vector<int> result;
    
    // Step 2: Initialize with the maximum possible combination
    maxHeap.push({A[0] + B[0], {0, 0}});
    visited.insert({0, 0});
    
    // Step 3: Pop C times to get the top C combinations
    for (int count = 0; count < C; count++) {
        // Extract the current maximum
        auto topElement = maxHeap.top();
        maxHeap.pop();
        
        int currentSum = topElement.first;
        int i = topElement.second.first;
        int j = topElement.second.second;
        
        result.push_back(currentSum);
        
        // Explore the neighbor one step down (i+1, j)
        if (i + 1 < n && visited.find({i + 1, j}) == visited.end()) {
            maxHeap.push({A[i + 1] + B[j], {i + 1, j}});
            visited.insert({i + 1, j});
        }
        
        // Explore the neighbor one step right (i, j+1)
        if (j + 1 < n && visited.find({i, j + 1}) == visited.end()) {
            maxHeap.push({A[i] + B[j + 1], {i, j + 1}});
            visited.insert({i, j + 1});
        }
    }
    
    return result;
}

12. Complexity Analysis

  • Time Complexity: * Sorting the two arrays takes O(NlogN)O(N \log N).
    • We run a loop CC times. Inside the loop, we push at most 2 elements into the Priority Queue. Insertion and extraction in a heap of size CC takes O(logC)O(\log C). Looking up a pair in the std::set takes O(logC)O(\log C).
    • Therefore, the heap/set operations take O(ClogC)O(C \log C).
    • Total Time Complexity: O(NlogN+ClogC)O(N \log N + C \log C). This easily passes the 10510^5 constraints.
  • Space Complexity:
    • The priority queue and the set will store at most O(C)O(C) elements at any given time.
    • Total Auxiliary Space Complexity: O(C)O(C).

13. Correctness Proof

Why are we absolutely sure no larger sum is skipped?

  1. Heap Property: We process items strictly in the order of their sum. The max-heap guarantees we always look at the absolute largest known candidate next.
  2. Monotonic Decay: Because the arrays are sorted descending, moving an index from ii to i+1i+1 or jj to j+1j+1 will strictly decrease or maintain the sum, never increase it.
  3. Frontier Connectivity: Any arbitrary valid coordinate (x, y) in our grid can be reached by a series of right and down moves starting from (0, 0). Because we push the immediate right and down neighbors of every maximum element we pop, the largest unknown elements are mathematically guaranteed to already be sitting inside the heap waiting to be evaluated.

Common Mistakes

Watch out for these frequent pitfalls during interviews:

  • Forgetting the Visited Set: This is the #1 mistake. Without a set, paths crossing at (i+1, j+1) will insert duplicate pairs into the heap, causing your answer to contain repeated values that shouldn't exist.
  • Using Ascending Sort by Accident: If you sort ascending and start from (0,0), you are actually finding the Minimum Sum Combinations. If you sort ascending, you MUST start from (N-1, N-1) and explore (i-1, j) and (i, j-1). It's much easier to just sort descending.
  • Looping N times instead of C times: The problem explicitly asks for the top CC combinations. Ensure your extraction loop runs strictly bounded by CC.

15. Pattern Recognition

How do you know an unseen problem uses this exact logic? Look for the "Matrix BFS / Dijkstra on Grid" pattern mixed with a Heap.

Indicators:

  1. The problem asks for the "Top KK" or "KK-th largest/smallest" of pairs or combinations from two sorted structures.
  2. Generating all combinations is technically possible but leads to O(N2)O(N^2) Memory/Time Limit Exceeded.
  3. The combinations can be visualized as a 2D grid where values strictly increase or decrease along rows and columns.

Video Reference:

reference

problem link:

https://www.naukri.com/code360/problems/k-max-sum-combinations_975322

CH

chakradhar

Author at SyntaxFlow