Start learning free

LESSON 274 OF 409 · BINARY SEARCH

Smallest K Integers V in O(n log maxVal) Time Complexity using C++

Practice O(n log n) 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 V) time, where V is the range of values in nums (from the smallest to the largest value).


STEP 1 OF 20
    Ctrl + Enter to check

    C++ · BINARY SEARCH

    Smallest K in C++, explained

    Understanding the Problem

    The core challenge of this problem is to find the smallest k integers from an array of positive integers efficiently. This problem is significant in scenarios where we need to quickly identify the smallest elements, such as in data analysis, statistics, and competitive programming. A common pitfall is to use sorting, which would result in a time complexity of O(n log n), not meeting the required O(n log maxVal) complexity.

    Approach

    To solve this problem, we need to think beyond simple sorting. Here are a few approaches:

    Naive Solution

    The naive solution would be to sort the array and then pick the first k elements. However, this approach has a time complexity of O(n log n), which is not optimal for this problem.

    Optimized Solution

    We can use a min-heap (priority queue) to keep track of the smallest k elements. This approach ensures that we only need to perform log(maxVal) operations for each element, resulting in the desired O(n log maxVal) time complexity.

    Algorithm

    Here is a step-by-step breakdown of the optimized algorithm:

    1. Initialize a min-heap (priority queue).
    2. Iterate through each element in the array.
    3. Push each element into the min-heap.
    4. If the size of the min-heap exceeds k, pop the largest element.
    5. After processing all elements, the min-heap will contain the smallest k elements.

    Code Implementation

    
    #include <iostream>
    #include <vector>
    #include <queue>
    #include <functional>
    
    std::vector<int> smallestKIntegers(const std::vector<int>& nums, int k) {
        // Min-heap to store the smallest k elements
        std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
    
        // Iterate through each element in the array
        for (int num : nums) {
            minHeap.push(num); // Push the current element into the min-heap
            if (minHeap.size() > k) {
                minHeap.pop(); // Remove the largest element if size exceeds k
            }
        }
    
        // Extract the smallest k elements from the min-heap
        std::vector<int> result;
        while (!minHeap.empty()) {
            result.push_back(minHeap.top());
            minHeap.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 << "Smallest " << k << " integers: ";
        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) because each insertion and deletion operation in the min-heap takes O(log k) time, and we perform these operations n times. The space complexity is O(k) for storing the k smallest elements in the min-heap.

    Edge Cases

    Potential edge cases include:

    • k is greater than the size of the array: In this case, the entire array should be returned.
    • k is zero: The result should be an empty array.
    • All elements in the array are the same: The result should contain k instances of that element.

    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, consider the following tips:

    • Understand the problem constraints and requirements thoroughly.
    • Think about different data structures and their time complexities.
    • Break down the problem into smaller steps and solve each step incrementally.
    • Practice similar problems to improve problem-solving skills and algorithmic thinking.

    Conclusion

    In this blog post, we discussed how to find the smallest k integers from an array efficiently using a min-heap. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving algorithmic thinking and 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