1

I have to find an algorithm for the following problem:

input are two numbers S and k of natural numbers and an unsorted set of n pair-wise different numbers.

decide in O(n) if there is a subset of k numbers that sum up to <=S. Note: k should not be part of the time complexity.

algorithm({x_1, ..., x_n}, k, S):
    if exists |{x_i, ..., x_j}| = k and x_i + ... x_j <= S return true

I don't find a solution with time complexity O(n).

What I was able to get is in O(kn), as we search k times the minimum and sum is up:

algorithm(a={x_1, ..., x_n}, k, S):
    sum = 0
    for i=1,...,k:
        min = a.popFirst()
        for i=2,...,len(a):
            if(a[i] < min):
                t = a[i]
                a[i] = min
                min = t
        sum += min
    if sum <= S:
        return true
    else:
        return false

this is in O(n) and return the right result. How can i loose the k?

Thanks for helping me, im really struggeling on this one!

gxor
  • 153
  • 7

2 Answers2

3

Quickselect can be used to find the k smallest elements: https://en.wikipedia.org/wiki/Quickselect

It's basically quicksort, except that you only recurse on the interesting side of the pivot.

A simple implementation runs in O(N) expected time, but using median-of-medians to select a pivot, you can make that a real worst-case bound: https://en.wikipedia.org/wiki/Median_of_medians

Matt Timmermans
  • 36,921
  • 2
  • 27
  • 59
  • But than I would need to find the k-smallest elements as well, don't I? This would mean I have O(kn) as well! I would still have to get these k elements to sum them up and check if there sum is < S – gxor Feb 27 '19 at 14:31
  • 1
    @gxor even if we just identify the `k`th smallest element, we can then filter the array in O(n). – גלעד ברקן Feb 27 '19 at 14:41
  • 1
    @gxor although it's often presented as an algorithm for finding the kth smallest element, quickselect does actually find the k smallest elements directly -- they'll be the first k elements in the array when it is done. – Matt Timmermans Feb 27 '19 at 15:32
2

You could build a min-heap of size k from the set. Time complexity of building this is O(n) expected time and O(n log k) worst case. The heap should contain first k minimum elements from the set.

Then it is straightforward to see the sum of the elements in the heap is <= S. You don't need to remove the elements from the heap to calculate the sum. Just traverse the heap to calculate sum. Removing all elements entails k log k complexity.

You don't even need to consider the next higher elements, because adding them would result in sum greater than S

SomeDude
  • 7,432
  • 4
  • 19
  • 33
  • What O(n) algorithm do you use to build the heap? Repeated insertion is worst-case O(n log k). (Expected time is O(n), if the inputs are randomly sorted. But no guarantees.) You could use first quickselect to partition elements, but if you did that the heap would be irrelevant. – rici Feb 27 '19 at 14:32
  • There is no specific algorithm. With the usual heapify i.e. sifting down the elements on the heap, tight bound of building a heap is `O(n)` because not all insertions are `O( log n )`. For an intuitive explanation, see [this](https://stackoverflow.com/a/9755805/1410303) beautiful answer. – SomeDude Feb 27 '19 at 15:14
  • that explains how to build a heap of `n` elements, not how to build a heap of the smallest `k` elements out of `n`. Those are different problems. If you already knew which `k` elements were desired, you could heapify in O(k), but in that case you would already have the answer. If you don't know, the standard heapify algorithm doesn't help you. – rici Feb 27 '19 at 15:50
  • @rici If you insert all n elements in the heap of size k, what would the heap contain? It contains k smallest elements. – SomeDude Feb 27 '19 at 18:41
  • that's correct, but it is not what heapify does. If you add `n` elements one at a time to a heap of size `k`, the cost is worst-case O(n log k). The heapify algorithm in your link rearranges `n` elements into a heap in guaranteed O(n), but it needs to have all the elements available to do that. It does not have a way of producing a smaller heap. – rici Feb 27 '19 at 19:16
  • By the way, see https://stackoverflow.com/questions/39514469/argument-for-o1-average-case-complexity-of-heap-insertion and the contained links for why the one-at-a-time insertion algorithm has *expected* linear time, although the worst-case time is log-linear and the probabilistic argument does not extend to amortised linear time, either. – rici Feb 27 '19 at 19:24
  • @rici Thanks for those links, they are definitely worth a read. I modified my answer. – SomeDude Mar 03 '19 at 15:06