Find K Closest Elements | Hello Interview

Heap

Find K Closest Elements

Description (inspired by Leetcode.com)

Given a sorted array nums, a target value target, and an integer k, find the k closest elements to target in the array, where "closest" is the absolute difference between each element and target. Return these elements in array, sorted in ascending order.

Example 1:

Inputs:

nums = [-1, 0, 1, 4, 6]
target = 1
k = 3

Output:

[-1, 0, 1]

Explanation: -1 is 2 away from 1, 0 is 1 away from 1, and 1 is 0 away from 1. All other elements are more than 2 away. Since we need to return the elements in ascending order, the answer is [-1, 0, 1]

Example 2:

Inputs:

nums = [5, 6, 7, 8, 9]
target = 10
k = 2

Output:

[8, 9]

💻 Desktop Required

The code editor works best on larger screens.

Explanation

Approach 1: Sorting

The simplest approach is to calculate the distance of each element from the target and to sort the elements based on that distance. This approach has a time complexity of O(n log n) where n is the number of points in the array, and a space complexity of O(n) (to store the sorted array of distances).

Approach 2: Max-Heap

This problem can be solved using a similar approach to the one used to solve Kth Largest Element in an Array, with the key difference being that we need to find the k closest elements to the target, rather than the k largest elements. Since we are looking for the k smallest elements, we need a max-heap, rather than a min-heap.

By default, python's heapq module implements a min-heap, but we can make it behave like a max-heap by negating the values of everything we push onto it.

First, we push the first k elements to the heap by storing a tuple containing the negative of the distance of the element from the target, and the element itself. After that is finished, our heap contains the k closest elements to the target that we've seen so far, with the element furthest from the target at the root of the heap.


def k_closest(nums, k, target):
    heap = []
    for num in nums:
        distance = abs(num - target)
        if len(heap) < k:
            heapq.heappush(heap, (-distance, num))
        elif distance < -heap[0][0]:
            heapq.heappushpop(heap, (-distance, num))

distances = [pair[1] for pair in heap]
    distances.sort()
    return distances

Complexity Analysis

Time Complexity: O(n * log k) where n is the number of elements in the array and k is the number of closest elements to find. We iterate over all the elements in the array. At each iteration, comparing the current element with the root of the heap takes O(1) time. In the worst case, we both push and pop each element from the heap, which takes O(log k) time.

Space Complexity: O(k) where k is the number of closest elements to find. The space used by the heap to store the k closest elements to the target.

Bonus Approach: Two Pointers + Binary Search

We can also leverage the fact that the input array is sorted to solve this problem using a two-pointer approach combined with binary search. This approach is based on the observation that the k closest elements to the target will occur in a contiguous subarray of length k in the sorted array.


def findClosestElements(nums, k, target):
    left, right = 0, len(nums) - k
    while left < right:
        mid = left + (right - left) // 2
        if target - nums[mid] > nums[mid + k] - target:
            left = mid + 1
        else:
            right = mid
    return nums[left:left + k]