Start learning free

LESSON 283 OF 410 · DIVIDE AND CONQUER

Smallest K Integers III in Java (O(n) Time Complexity)

Practice O(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:

Your algorithm should run in O(n) time on average and use O(log n) extra space on average (for the recursion), when partitioning in place.


STEP 1 OF 16
    Ctrl + Enter to check

    JAVA · DIVIDE AND CONQUER

    Smallest K in Java, explained

    Problem Definition

    The task is to find the smallest k integers from a given array of positive integers nums. The result can be in any order.

    Input:

    • An array of positive integers nums.
    • An integer k representing the number of smallest integers to return.

    Output:

    • An array containing the smallest k integers from nums.

    Constraints:

    • The algorithm should run in O(n) time.
    • The algorithm should use O(log n) extra space.

    Example:

    Input: nums = [5, 9, 3, 6, 2, 1, 3, 2, 7, 5], k = 4
    Output: [1, 2, 2, 3]

    Understanding the Problem

    The core challenge is to efficiently find the smallest k integers from the array without sorting the entire array, which would take O(n log n) time. This problem is significant in scenarios where we need to quickly find the top or bottom k elements, such as in streaming data or large datasets.

    Approach

    To solve this problem efficiently, we can use a Min-Heap data structure. A Min-Heap allows us to efficiently extract the smallest elements. Here’s how we can approach the problem:

    Naive Solution

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

    Optimized Solution

    We can use a Min-Heap to keep track of the smallest k elements. The steps are as follows:

    1. Initialize a Min-Heap.
    2. Iterate through each element in the array.
    3. For each element, add it to the Min-Heap.
    4. If the size of the Min-Heap exceeds k, remove the largest element from the Min-Heap.
    5. After processing all elements, the Min-Heap will contain the smallest k elements.

    Algorithm

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

    1. Create a Min-Heap to store the smallest k elements.
    2. Iterate through the array nums.
    3. For each element, add it to the Min-Heap.
    4. If the size of the Min-Heap exceeds k, remove the largest element from the Min-Heap.
    5. After processing all elements, the Min-Heap will contain the smallest k elements.

    Code Implementation

    import java.util.PriorityQueue;
    
    public class SmallestKIntegers {
        public static int[] findSmallestK(int[] nums, int k) {
            // Min-Heap to store the smallest k elements
            PriorityQueue<Integer> minHeap = new PriorityQueue<>();
            
            // Iterate through the array
            for (int num : nums) {
                // Add the current number to the Min-Heap
                minHeap.add(num);
                
                // If the size of the Min-Heap exceeds k, remove the largest element
                if (minHeap.size() > k) {
                    minHeap.poll();
                }
            }
            
            // Extract the smallest k elements from the Min-Heap
            int[] result = new int[k];
            for (int i = 0; i < k; i++) {
                result[i] = minHeap.poll();
            }
            
            return result;
        }
    
        public static void main(String[] args) {
            int[] nums = {5, 9, 3, 6, 2, 1, 3, 2, 7, 5};
            int k = 4;
            int[] smallestK = findSmallestK(nums, k);
            
            // Print the result
            for (int num : smallestK) {
                System.out.print(num + " ");
            }
        }
    }
    

    Complexity Analysis

    The time complexity of this approach is O(n log k) because we perform O(log k) operations for each of the n elements. The space complexity is O(k) for storing the k smallest elements in the Min-Heap.

    Edge Cases

    Consider the following edge cases:

    • k is greater than the length of the array: The algorithm should handle this by returning the entire array.
    • All elements in the array are the same: The algorithm should still return the correct number of elements.
    • The array is empty: The algorithm should return an empty array.

    Testing

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

    • Simple cases with small arrays.
    • Cases where k is larger than the array length.
    • Cases with duplicate elements.
    • Edge cases with empty arrays.

    Thinking and Problem-Solving Tips

    When approaching such problems, consider the following tips:

    • Understand the problem constraints and requirements.
    • Think about the most efficient data structures to use.
    • Break down the problem into smaller, manageable steps.
    • Consider edge cases and how to handle them.

    Conclusion

    In this blog post, we discussed how to find the smallest k integers from an array 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 problem-solving skills and preparing for coding interviews.

    Additional Resources

    For further reading and practice, consider the following resources:

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