Find minimum subset that sum to at least K | Yaozong's Blog
Given a list of n integers, write a function that outputs the minimum subset of numbers that sum to at least K.
Follow up: can you beat O(nlogn)?
Solution 1: sort and linear search O(nlogn)
https://www.quora.com/Find-the-maximum-sum-of-k-length-subset-of-a-given-set-such-that-sum-is-strictly-less-than-M
Read full article from Find minimum subset that sum to at least K | Yaozong's Blog
Given a list of n integers, write a function that outputs the minimum subset of numbers that sum to at least K.
Follow up: can you beat O(nlogn)?
Solution 1: sort and linear search O(nlogn)
vector<int> minimum_subset_sum_atleast_K(vector<int>& vec, int K)
{
if(vec.size() == 0)
return {};
sort(vec.begin(), vec.end());
int n = vec.size();
vector<int> res(1, vec.back());
int cumsum = vec.back();
for(int i = n - 2; i >= 0; --i)
{
if(vec[i] < 0 || cumsum >= K) break;
cumsum += vec[i];
res.push_back(vec[i]);
}
if(cumsum >= K)
return res;
else
return {};
}
|
Solution 2: Selection Algorithm O(n) on average
http://tristan-interview.blogspot.com/2012/03/find-minimum-set-of-numbers-that-sum-to.html
Here we introduce a selection based algorithm which on average costs O(n) but costs O(n^2) in the worst case. The approach is similar to kth order-statistics.
- Randomly choose a pivot from the current array and partition the array into two parts p1 and p2: p1 contains integers which are smaller than the pivot; p2 contains integers which are larger than or equal to the pivot.
- Check if pivot + sum(p2) == K, if so, we already find the answer; if not, then if pivot + sum(p2) > K but sum(p2) <= K, we also find the answer; if sum(p2) > K, we need to do further partition, but we just need to further partition p2; if pivot + sum(p2) < K, we need to do further partition, but we need to partition p1 instead and the target value K is updated as K - pivot - sum(p2).
void find_min_set(int *a, int start, int end, int target)
{
/* generate secret number: */
int s, e, k;
s = start;
e = end;
k = target;
int sum;
while(1)
{
srand ( time(NULL) );
int idx = ((int)rand()) % (e-s + 1) + s;
/* partition and sum */
int tmp = a[idx];
a[idx] = a[e];
a[e] = tmp;
sum = a[e];
int pos = s;
for(int i = s; i < e; i++)
{
if(a[i] < a[e])
{
if(pos != i)
{
tmp = a[pos];
a[pos] = a[i];
a[i] = tmp;
}
pos++;
}
else sum+= a[i];
}
tmp = a[pos];
a[pos] = a[e];
a[e] = tmp;
if(sum == k)
{
cout << "found " << endl;
return;
}
else if(sum > k)
{
if(sum - a[pos] < k)
{
cout << "found " << endl;
return;
}
s = pos + 1;
sum = 0;
}
else
{
k = k - sum;
sum = 0;
e = pos - 1;
}
}
}
vector<int> quick_select(vector<int>& vec, int i, int j, int K)
{
if(i > j)
return {};
if(i == j)
return {vec[i]};
int len = j - i + 1;
int idx = rand() % len + i;
int pivot = vec[idx];
swap(vec[idx], vec[j]);
int p = i, q = j;
int left_sum = vec[idx], right_sum = 0;
while(p < q) {
if(vec[p] <= pivot) {
left_sum += vec[p];
++ p;
} else {
right_sum += vec[p];
swap(vec[p], vec[--q]);
}
}
swap(vec[q], vec[j]);
vector<int> res;
if(right_sum == K) {
if(q + 1 <= j)
res.insert(res.end(), vec.begin()+q+1, vec.begin()+j+1);
return res;
}
else if(right_sum > K) {
return quick_select(vec, q+1, j, K);
}
else {
if(q + 1 <= j)
res.insert(res.end(), vec.begin()+q+1, vec.begin()+j+1);
K = K - right_sum;
vector<int> res2 = quick_select(vec, i, q, K);
res.insert(res.end(), res2.begin(), res2.end());
return res;
}
}
vector<int> minimum_subset_sum_atleast_K(vector<int>& vec, int K)
{
if(vec.size() == 0)
return {};
vector<int> res = quick_select(vec, 0, vec.size() - 1, K);
int sum = accumulate(res.begin(), res.end(), 0);
if(sum >= K)
return res;
else
return {};
}
https://www.quora.com/Find-the-maximum-sum-of-k-length-subset-of-a-given-set-such-that-sum-is-strictly-less-than-M
Read full article from Find minimum subset that sum to at least K | Yaozong's Blog