Start learning free

LESSON 311 OF 409 · HEAP

Smallest K Integers II in C++ (O(n log k) Time Complexity)

Practice O(n log k) Read the full explanation

Given an array of positive integers nums, return the smallest k values, in any order you want.

Example:

Input: nums = [5, 9, 3, 6, 2, 1, 3, 2, 7, 5], k = 4
Output: [1, 2, 2, 3]
Explanation: Smallest number is 1, 2nd smallest is 2, 
            3rd smallest is 2, 4th smallest is 3
The result can be in any order, [2, 1, 3, 2] is also a correct answer.

Note:

For this lesson, your algorithm should run in O(n log k) time and use O(k) extra space.
(There are faster solutions which we will discuss in future lessons)


STEP 1 OF 8
    Ctrl + Enter to check

    C++ · HEAP

    Smallest K in C++, explained

    Understanding the Problem

    The core challenge of this problem is to efficiently find the smallest k integers from an array of positive integers. This problem is significant in scenarios where we need to filter out the smallest elements from a large dataset, such as in data analysis, statistics, and competitive programming.

    Potential pitfalls include misunderstanding the requirement to return the smallest k values in any order and not optimizing the solution to meet the required time and space complexity.

    Approach

    To solve this problem, we can use a max-heap (priority queue) to keep track of the smallest k elements. The idea is to maintain a heap of size k. As we iterate through the array, we add elements to the heap. If the heap exceeds size k, we remove the largest element (the root of the max-heap). This ensures that the heap always contains the k smallest elements.

    Here is a step-by-step approach:

    1. Initialize a max-heap (priority queue) to store the smallest k elements.
    2. Iterate through each element in the array.
    3. Add the current element to the heap.
    4. If the heap size exceeds k, remove the largest element from the heap.
    5. After processing all elements, the heap contains the k smallest elements.

    Algorithm

    Let's break down the algorithm step-by-step:

    1. Create a max-heap to store the smallest k elements.
    2. Iterate through the array:
      • Add the current element to the heap.
      • If the heap size exceeds k, remove the largest element from the heap.
    3. Return the elements in the heap as the result.

    Code Implementation

    
    #include <iostream>
    #include <vector>
    #include <queue>
    #include <functional>
    
    std::vector<int> smallestKIntegers(const std::vector<int>& nums, int k) {
        // Max-heap to store the smallest k elements
        std::priority_queue<int> maxHeap;
    
        // Iterate through each element in the array
        for (int num : nums) {
            // Add the current element to the heap
            maxHeap.push(num);
    
            // If the heap size exceeds k, remove the largest element
            if (maxHeap.size() > k) {
                maxHeap.pop();
            }
        }
    
        // Extract the elements from the heap
        std::vector<int> result;
        while (!maxHeap.empty()) {
            result.push_back(maxHeap.top());
            maxHeap.pop();
        }
    
        return result;
    }
    
    int main() {
        std::vector<int> nums = {5, 9, 3, 6, 2, 1, 3, 2, 7, 5};
        int k = 4;
        std::vector<int> result = smallestKIntegers(nums, k);
    
        std::cout << "The smallest " << k << " integers are: ";
        for (int num : result) {
            std::cout << num << " ";
        }
        std::cout << std::endl;
    
        return 0;
    }
    

    Complexity Analysis

    The time complexity of this approach is O(n log k), where n is the number of elements in the array. This is because we perform log k operations for each of the n elements when maintaining the heap of size k. The space complexity is O(k) since we store only k elements in the heap.

    Edge Cases

    Potential edge cases include:

    • k is greater than the number of elements in the array. In this case, the result should be the entire array.
    • k is zero. The result should be an empty array.
    • All elements in the array are the same. The result should contain k of those elements.

    Testing

    To test the solution comprehensively, consider the following test cases:

    • Simple cases with small arrays and small k values.
    • Edge cases where k is zero or greater than the array size.
    • Arrays with duplicate elements.
    • Large arrays to test the efficiency of the algorithm.

    Thinking and Problem-Solving Tips

    When approaching such problems, it's essential to:

    • Understand the problem requirements and constraints thoroughly.
    • Consider different data structures and their properties to find the most efficient solution.
    • Break down the problem into smaller steps and solve each step methodically.
    • Practice similar problems to improve problem-solving skills and familiarity with different algorithms.

    Conclusion

    In this blog post, we discussed how to find the smallest k integers from an array using a max-heap. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for developing efficient algorithms and improving problem-solving skills.

    Additional Resources

    For further reading and practice, consider the following resources:

    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free