I was doing this exercise in my computer science class for a warm up earlier, which was to find the minimum number of moves to make all the elements in an array equal to each other, where the only operation is to subtract one from an element in an array.
This made me curious about extensions to the problem; for example I immediately thought of an extension, how many moves will it take to make all the elements in an array equal to each other, where the only operation is to subtract one from two elements that are adjacent to each other.
For example:
Given array [4, 6, 4], we can decrease elements in index 0 and 1 to get [3, 5, 4], then [3, 4, 3], then [2, 3, 3], and then decrease elements in index 1 and 2 to get [2, 2, 2]. This would take 4 moves. However, how would we extend this kind of thinking to larger arrays, where we cannot trace this out by hand like I just did above?
You can find whether this is possible (and minimum number of moves) in O(n) time, in a way that should generalize to larger array decreases.
The first step is to convert our array A to the first-difference array D, whose elements are D = [A[1]-A[0], A[2]-A[1], ..., A[n-1]-A[n-2]]. We are done when D is the all-zero array. Now, think about how the operations on A translate to changes in D. It's different when n is even and odd, too, so focus on one case at a time.
Odd length
When A has odd length, there are more cases where no solution is possible.
Suppose 'A' has 7 elements. There's 6 possible moves, so let's calculate what effect each has on D.
A = [a_0, a_1, a_2, a_3, a_4, a_5, a_6]
D = [d_0, d_1, d_2, d_3, d_4, d_5]
Moves available:
d_1 += 1
(d_0 -= 1, d_2 += 1)
(d_1 -= 1, d_3 += 1)
(d_2 -= 1, d_4 += 1)
(d_3 -= 1, d_5 += 1)
d_4 -= 1
Some observations:
The interactions between even and odd indices of D are completely disjoint (this is true for the even-length case too).
d_5 can only increase, d_0 can only decrease.
I found it helpful to think of this as a 'flow' from left to right in D:
d_0 --> d_2 --> d_4 --> SINK
SOURCE --> d_1 --> d_3 --> d_5
this makes things easier: there's only one way to try to make D all zero, so we can just try that.
If D[0] is negative, this is impossible. If it's positive, add D[0] moves to our counter, and add D[0] to D[2]
If D[2] is negative, this is impossible. If it's positive, add D[2] moves to our counter, and add D[2] to D[4]
If D[4] is negative, this is impossible. Otherwise, add D[4] to our counter. D[4] points to a sink, so we are done.
I haven't explained the process for the odd vertices, but it's the same logic-- there's at most one way to make D all zero, following the flow.
Even-length
The even-length array case is similar, except the flow-network has different endpoints.
A = [a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7]
D = [d_0, d_1, d_2, d_3, d_4, d_5, d_6]
Moves available:
d_1 += 1
(d_0 -= 1, d_2 += 1)
(d_1 -= 1, d_3 += 1)
(d_2 -= 1, d_4 += 1)
(d_3 -= 1, d_5 += 1)
(d_4 -= 1, d_6 += 1)
d_5 -= 1
d_0 --> d_2 --> d_4 --> d_6
SOURCE --> d_1 --> d_3 --> d_5 --> SINK
This means that the odd-indices can have any values without changing the solvability, while the even indices must become all zero with only positive transfers from left to right. Positive flow still moves in exactly one direction in both cases.
I've written a Python solution implementing the logic above. There's one caveat-- I haven't been able to rigorously test it against random input. There's no obviously correct brute-force solution to this problem, so there may be failing testcases that I missed.
def min_decreases_to_get_equal(nums: List[int]) -> Optional[int]:
"""Given an array of integers, returns the number of moves
to make all elements equal, or None if impossible.
A move is selecting two adjacent elements and dec. both by 1."""
n = len(nums)
assert n >= 2
if n == 2:
return 0 if nums[0] == nums[1] else None
differences = [nums[i] - nums[i - 1] for i in range(1, n)]
evens = differences[0::2]
odds = differences[1::2]
if n % 2 == 0: # Even length case
total_cost = 0
m1 = len(evens)
for i, x in enumerate(evens):
if x < 0:
return None
elif x > 0:
# Last element can't be decreased
if i == m1 - 1:
return None
total_cost += abs(x)
evens[i + 1] += abs(x)
m2 = len(odds)
for i, x in enumerate(odds):
if x < 0:
total_cost += abs(x) * (i + 1)
elif x > 0:
total_cost += abs(x)
if i < m2 - 1:
odds[i + 1] += x
return total_cost
else: # Odd length case
total_cost = 0
m1 = len(evens)
for i, x in enumerate(evens):
if x < 0:
return None
elif x > 0:
if i < m1 - 1:
evens[i + 1] += abs(x)
total_cost += abs(x)
m2 = len(odds)
for i in reversed(range(m2)):
x = odds[i]
if x < 0:
if i != 0:
odds[i - 1] -= abs(x)
total_cost += abs(x)
elif x > 0:
return None
return total_cost
Example tests:
[4, 6, 4] --> 4,
[3, 2, 3] --> None,
[0, 8, 8, 14, 8] --> 34,
[2, 5, 1, 6, 12, 11, 7, 0, 1, 1] --> 33
Let's start with the problem that we want to find out what is the smallest number of operations. If we know what is the largest number that equalizes all arrays? We can subtract that number from each other in the array to get the answer. Naively, you can solve this problem by searching for the smallest number in the array and loop checking from 0 to min(a[i]) then find the minimum operations.
My code in C++
// print -1 if not possible to equalize array
void solve() {
int N;
scanf("%d", &N);
vector<int> a(N);
int minimum=INT_MAX;
for(int i=0; i<N; ++i) {
scanf("%d", &a[i]);
minimum=min(minimum, a[i]);
}
if(N==1) { // Initially check when N=1 or N=2
printf("0\n");
return;
}
else if(N==2) {
printf("%d\n", (a[0]==a[1] ? 0 : -1));
return;
}
vector<int> temp=a; // temporary array for storing array before operation
for(int target=minimum; target>=0; --target) {
a=temp;
bool check=true; // check array equal?
int operation=0; // count number operations
for(int j=0; j<N-1; ++j) {
int subtract=a[j]-target;
operation+=2*subtract;
a[j]-=subtract;
a[j+1]-=subtract;
if(a[j]<target || a[j+1]<target) { // all element should equal to target
check=false;
break;
}
}
if(check==true) {
printf("%d\n", operation);
return;
}
}
printf("-1\n"); // not possible
}
But the above method will be slow when N is large.
For this problem, the Greedy Algorithm can be used to solve it. Now let's look at the situations when this array can't be equalized. If you want to make an array with a[i-1] != a[i] to be equal, what do you have to do? Assume we're iterating over an array and come into the following cases.
First, if a[i-1] > a[i] , then we have to perform operation at the left-hand in order to equal make it to the right-hand side, that is, a[i-2] and a[i-1] must be executed. For example 8 8 7 to 7 7 7.
Please note that if i equals 1, it needs the initial element of an array. It will be unable to operate.
Second, if a[i-1] < a[i] , then we have to perform operation at the right-hand in order to make it equal to the left-hand side, that is, a[i] and a[i+1] must be executed. For example 5 6 6 to 5 5 5.
Please note that if i equals N-1, it is the last element of an array. It will be unable to operate. Naturally, the prior ones have been equalized.
After that, we can use Greedy to keep the array equal. We'll traverse over the array one by one, checking for the conditions listed above. If it can do it, it ought to. Continue until you are unable to do so or discover that this array is stuck at the very first or final position. This one will be quicker than the previous one.
Here is my code.
// print -1 if not possible to equalize array
void solve() {
int N;
scanf("%d", &N);
vector<int> a(N);
for(int i=0; i<N; ++i) {
scanf("%d", &a[i]);
}
if(N==1) {
printf("0\n");
return;
}
else if(N==2) {
printf("%d\n", (a[0]==a[1] ? 0 : -1));
return;
}
if(a[N-2]<a[N-1] || a[0]>a[1]) {
printf("-1\n");
return;
}
long long operation=0;
bool check=true; // check if the array has changed
while(check) {
check=false;
for(int i=1; i<N; ++i) {
if(a[i-1]<a[i]) {
if(i==N-1) {
printf("-1\n");
return;
}
check=true;
int subtract=a[i]-a[i-1];
operation+=2*subtract;
a[i]-=subtract;
a[i+1]-=subtract;
if(a[i]<0 || a[i+1]<0) {
printf("-1\n");
return;
}
}
else if(a[i-1]>a[i]) {
if(i==1) {
printf("-1\n");
return;
}
check=true;
int subtract=a[i-1]-a[i];
operation+=2*subtract;
a[i-2]-=subtract;
a[i-1]-=subtract;
if(a[i-2]<0 || a[i-1]<0) {
printf("-1\n");
return;
}
}
}
}
printf("%lld\n", (a[N-1]>=0 ? operation : -1)); // array already equal but may less than zero
}
This may be accomplished in a variety of ways, and there is a better approach than the one I've presented. However, I believe that this is sufficient to go through test cases 1 <= N <= 105 and 0 <= a[i] <= 109.
Related
Given an array of n elements, how do I find the number of ranges [min(A[i], A[i+1]), max(A[i], A[i+1])] which contains a given value k. Here i lies between 0 <= a < b < n for zero-based indexing, where a and b are zero-based indexes.
For example, for the below array with a = 1, and b = 3;
6 3 2 8 5
Suppose for k = 3, it has to be found in range [min(A[1], A[2]), max(A[1], A[2])] and [min(A[2], A[3]), max(A[2], A[3])]. Here k=3 appears in both the ranges [2, 3] and [2, 8] so the answer is 2.
How could I find the count of ranges in less than linear time with certain pre-computation?
I don't need the exact code, just a high level overview of the approach/data structure would do.
Thanks in advance!
You can save some time by previously kicking out all elements i of the array A which fullfill (A[i-1] <= A[i] and A[i] <= A[i+1]) or ((A[i-1] >= A[i] and A[i] >= A[i+1]). Then counting the valid interval range number should still be the same.
int ctr = 0;
for(i=a;i<b-1;i++)
{
if ( (A[i]<=k && A[i+1]>= k) || (A[i]>=k && A[i+1]<= k) )
ctr++;
}
printf(" Count: %i", ctr);
User will input five values (range 2-9), into an array. Code is then supposed to check whether or not the five values entered are either in decreasing or increasing order.
Example:
2, 3, 4, 5, 6 - would result in a bool value set to 'true'
6, 5, 4, 3, 2 - would have the same result as above
If however there are two of the same numbers or the sequence is not in order, either increasing or decreasing then the bool value is 'false'
Example:
2, 3, 2, 5, 6 - false
2, 3, 5, 4, 6 - false
7, 8, 6, 5, 4 - false
I have completed two cases individually, when there is a pair and when checking for increasing order.
For loop I have set up to check increasing order/pair
for(int count = 0; count < 5; count++){
if((cards[count] > cards[count + 1]) || (cards[count] == cards[count + 1]))
result = false;
else
continue;
}
For loop I made to check decreasing order
for(int count = 0; count < 5; count++){
if((cards[count] < cards[count+ 1]) || (cards[count] == cards[count + 1]))
result = false;
else
continue;
}
The for loop that is meant to check increasing order does not work, and lastly putting it all together. I tried breaking it down into individuals parts in order to make it easier.
Edit:
per assignment guidelines, I am unable to sort the array or anything that modifies it. creating a copy and working with that is also not allowed.
First, you don't need the else continue; – that will happen automatically.
Second, you're on the right track, but you have an error in your array accesses. Your loop goes from 0 to 4 (when it reaches 5 it will end the loop). When you're looking at item 4 (the 5th item in the array) of the array and compare it to item 5 (the sixth item in the array), you're comparing against a value that isn't there. This can cause undefined behavior.
The solution is to set the condition on your loop to < 4 so that on the last loop you compare the second-to-last item with the last item.
You can check monotonicity in one loop.
bool isArrayMonotonic(std::vector<int>& arr) {
if (arr.empty()) {
return true;
}
bool isAscending = true, isDescending = true;
int pre = arr[0];
for (int i = 1; i < arr.size(); ++i) {
isAscending = isAscending && arr[i] > pre;
isDescending = isDescending && arr[i] < pre;
pre = arr[i];
}
return isAscending || isDescending;
}
On this years Bubble Cup (finished) there was the problem NEO (which I couldn't solve), which asks
Given array with n integer elements. We divide it into several part (may be 1), each part is a consecutive of elements. The NEO value in that case is computed by: Sum of value of each part. Value of a part is sum all elements in this part multiple by its length.
Example: We have array: [ 2 3 -2 1 ]. If we divide it like: [2 3] [-2 1]. Then NEO = (2 + 3) * 2 + (-2 + 1) * 2 = 10 - 2 = 8.
The number of elements in array is smaller then 10^5 and the numbers are integers between -10^6 and 10^6
I've tried something like divide and conquer to constantly split array into two parts if it increases the maximal NEO number otherwise return the NEO of the whole array. But unfortunately the algorithm has worst case O(N^2) complexity (my implementation is below) so I'm wondering whether there is a better solution
EDIT: My algorithm (greedy) doesn't work, taking for example [1,2,-6,2,1] my algorithm returns the whole array while to get the maximal NEO value is to take parts [1,2],[-6],[2,1] which gives NEO value of (1+2)*2+(-6)+(1+2)*2=6
#include <iostream>
int maxInterval(long long int suma[],int first,int N)
{
long long int max = -1000000000000000000LL;
long long int curr;
if(first==N) return 0;
int k;
for(int i=first;i<N;i++)
{
if(first>0) curr = (suma[i]-suma[first-1])*(i-first+1)+(suma[N-1]-suma[i])*(N-1-i); // Split the array into elements from [first..i] and [i+1..N-1] store the corresponding NEO value
else curr = suma[i]*(i-first+1)+(suma[N-1]-suma[i])*(N-1-i); // Same excpet that here first = 0 so suma[first-1] doesn't exist
if(curr > max) max = curr,k=i; // find the maximal NEO value for splitting into two parts
}
if(k==N-1) return max; // If the max when we take the whole array then return the NEO value of the whole array
else
{
return maxInterval(suma,first,k+1)+maxInterval(suma,k+1,N); // Split the 2 parts further if needed and return it's sum
}
}
int main() {
int T;
std::cin >> T;
for(int j=0;j<T;j++) // Iterate over all the test cases
{
int N;
long long int NEO[100010]; // Values, could be long int but just to be safe
long long int suma[100010]; // sum[i] = sum of NEO values from NEO[0] to NEO[i]
long long int sum=0;
int k;
std::cin >> N;
for(int i=0;i<N;i++)
{
std::cin >> NEO[i];
sum+=NEO[i];
suma[i] = sum;
}
std::cout << maxInterval(suma,0,N) << std::endl;
}
return 0;
}
This is not a complete solution but should provide some helpful direction.
Combining two groups that each have a positive sum (or one of the sums is non-negative) would always yield a bigger NEO than leaving them separate:
m * a + n * b < (m + n) * (a + b) where a, b > 0 (or a > 0, b >= 0); m and n are subarray lengths
Combining a group with a negative sum with an entire group of non-negative numbers always yields a greater NEO than combining it with only part of the non-negative group. But excluding the group with the negative sum could yield an even greater NEO:
[1, 1, 1, 1] [-2] => m * a + 1 * (-b)
Now, imagine we gradually move the dividing line to the left, increasing the sum b is combined with. While the expression on the right is negative, the NEO for the left group keeps decreasing. But if the expression on the right gets positive, relying on our first assertion (see 1.), combining the two groups would always be greater than not.
Combining negative numbers alone in sequence will always yield a smaller NEO than leaving them separate:
-a - b - c ... = -1 * (a + b + c ...)
l * (-a - b - c ...) = -l * (a + b + c ...)
-l * (a + b + c ...) < -1 * (a + b + c ...) where l > 1; a, b, c ... > 0
O(n^2) time, O(n) space JavaScript code:
function f(A){
A.unshift(0);
let negatives = [];
let prefixes = new Array(A.length).fill(0);
let m = new Array(A.length).fill(0);
for (let i=1; i<A.length; i++){
if (A[i] < 0)
negatives.push(i);
prefixes[i] = A[i] + prefixes[i - 1];
m[i] = i * (A[i] + prefixes[i - 1]);
for (let j=negatives.length-1; j>=0; j--){
let negative = prefixes[negatives[j]] - prefixes[negatives[j] - 1];
let prefix = (i - negatives[j]) * (prefixes[i] - prefixes[negatives[j]]);
m[i] = Math.max(m[i], prefix + negative + m[negatives[j] - 1]);
}
}
return m[m.length - 1];
}
console.log(f([1, 2, -5, 2, 1, 3, -4, 1, 2]));
console.log(f([1, 2, -4, 1]));
console.log(f([2, 3, -2, 1]));
console.log(f([-2, -3, -2, -1]));
Update
This blog provides that we can transform the dp queries from
dp_i = sum_i*i + max(for j < i) of ((dp_j + sum_j*j) + (-j*sum_i) + (-i*sumj))
to
dp_i = sum_i*i + max(for j < i) of (dp_j + sum_j*j, -j, -sum_j) ⋅ (1, sum_i, i)
which means we could then look at each iteration for an already seen vector that would generate the largest dot product with our current information. The math alluded to involves convex hull and farthest point query, which are beyond my reach to implement at this point but will make a study of.
Example:
Input: | Output:
5 –> 12 (1^2 + 2^2 = 5)
500 -> 18888999 (1^2 + 8^2 + 8^2 + 8^2 + 9^2 + 9^2 + 9^2 = 500)
I have written a pretty simple brute-force solution, but it has big performance problems:
#include <iostream>
using namespace std;
int main() {
int n;
bool found = true;
unsigned long int sum = 0;
cin >> n;
int i = 0;
while (found) {
++i;
if (n == 0) { //The code below doesn't work if n = 0, so we assign value to sum right away (in case n = 0)
sum = 0;
break;
}
int j = i;
while (j != 0) { //After each iteration, j's last digit gets stripped away (j /= 10), so we want to stop right when j becomes 0
sum += (j % 10) * (j % 10); //After each iteration, sum gets increased by *(last digit of j)^2*. (j % 10) gets the last digit of j
j /= 10;
}
if (sum == n) { //If we meet our problem's requirements, so that sum of j's each digit squared is equal to the given number n, loop breaks and we get our result
break;
}
sum = 0; //Otherwise, sum gets nullified and the loops starts over
}
cout << i;
return 0;
}
I am looking for a fast solution to the problem.
Use dynamic programming. If we knew the first digit of the optimal solution, then the rest would be an optimal solution for the remainder of the sum. As a result, we can guess the first digit and use a cached computation for smaller targets to get the optimum.
def digitsum(n):
best = [0]
for i in range(1, n+1):
best.append(min(int(str(d) + str(best[i - d**2]).strip('0'))
for d in range(1, 10)
if i >= d**2))
return best[n]
Let's try and explain David's solution. I believe his assumption is that given an optimal solution, abcd..., the optimal solution for n - a^2 would be bcd..., therefore if we compute all the solutions from 1 to n, we can rely on previous solutions for numbers smaller than n as we try different subtractions.
So how can we interpret David's code?
(1) Place the solutions for the numbers 1 through n, in order, in the table best:
for i in range(1, n+1):
best.append(...
(2) the solution for the current query, i, is the minimum in an array of choices for different digits, d, between 1 and 9 if subtracting d^2 from i is feasible.
The minimum of the conversion to integers...
min(int(
...of the the string, d, concatenated with the string of the solution for n - d^2 previously recorded in the table (removing the concatenation of the solution for zero):
str(d) + str(best[i - d**2]).strip('0')
Let's modify the last line of David's code, to see an example of how the table works:
def digitsum(n):
best = [0]
for i in range(1, n+1):
best.append(min(int(str(d) + str(best[i - d**2]).strip('0'))
for d in range(1, 10)
if i >= d**2))
return best # original line was 'return best[n]'
We call, digitsum(10):
=> [0, 1, 11, 111, 2, 12, 112, 1112, 22, 3, 13]
When we get to i = 5, our choices for d are 1 and 2 so the array of choices is:
min([ int(str(1) + str(best[5 - 1])), int(str(2) + str(best[5 - 4])) ])
=> min([ int( '1' + '2' ), int( '2' + '1' ) ])
And so on and so forth.
So this is in fact a well known problem in disguise. The minimum coin change problem in which you are given a sum and requested to pay with minimum number of coins. Here instead of ones, nickels, dimes and quarters we have 81, 64, 49, 36, ... , 1 cents.
Apparently this is a typical example to encourage dynamic programming. In dynamic programming, unlike in recursive approach in which you are expected to go from top to bottom, you are now expected to go from bottom to up and "memoize" the results those will be required later. Thus... much faster..!
So ok here is my approach in JS. It's probably doing a very similar job to David's method.
function getMinNumber(n){
var sls = Array(n).fill(),
sct = [], max;
sls.map((_,i,a) => { max = Math.min(9,~~Math.sqrt(i+1)),
sct = [];
while (max) sct.push(a[i-max*max] ? a[i-max*max].concat(max--)
: [max--]);
a[i] = sct.reduce((p,c) => p.length < c.length ? p : c);
});
return sls[sls.length-1].reverse().join("");
}
console.log(getMinNumber(500));
What we are doing is from bottom to up generating a look up array called sls. This is where memoizing happens. Then starting from from 1 to n we are mapping the best result among several choices. For example if we are to look for 10's partitions we will start with the integer part of 10's square root which is 3 and keep it in the max variable. So 3 being one of the numbers the other should be 10-3*3 = 1. Then we look up for the previously solved 1 which is in fact [1] at sls[0] and concat 3 to sls[0]. And the result is [3,1]. Once we finish with 3 then one by one we start over the same job with one smaller, up until it's 1. So after 3 we check for 2 (result is [2,2,1,1]) and then for 1 (result is [1,1,1,1,1,1,1,1,1,1]) and compare the length of the results of 3, 2 and 1 for the shortest, which is [3,1] and store it at sls[9] (a.k.a a[i]) which is the place for 10 in our look up array.
(Edit) This answer is not correct. The greedy approach does not work for this problem -- sorry.
I'll give my solution in a language agnostic fashion, i.e. the algorithm.
I haven't tested but I believe this should do the trick, and the complexity is proportional to the number of digits in the output:
digitSquared(n) {
% compute the occurrences of each digit
numberOfDigits = [0 0 0 0 0 0 0 0 0]
for m from 9 to 1 {
numberOfDigits[m] = n / m*m;
n = n % m*m;
if (n==0)
exit loop;
}
% assemble the final output
output = 0
powerOfTen = 0
for m from 9 to 1 {
for i from 0 to numberOfDigits[m] {
output = output + m*10^powerOfTen
powerOfTen = powerOfTen + 1
}
}
}
I am a newbie in C++ and need logical help in the following task.
Given a sequence of n positive integers (n < 10^6; each given integer is less than 10^6), write a program to find the smallest positive integer, which cannot be expressed as a sum of 1, 2, or more items of the given sequence (i.e. each item could be taken 0 or 1 times). Examples: input: 2 3 4, output: 1; input: 1 2 6, output: 4
I cannot seem to construct the logic out of it, why the last output is 4 and how to implement it in C++, any help is greatly appreciated.
Here is my code so far:
#include<iostream>
using namespace std;
const int SIZE = 3;
int main()
{
//Lowest integer by default
int IntLowest = 1;
int x = 0;
//Our sequence numbers
int seq;
int sum = 0;
int buffer[SIZE];
//Loop through array inputting sequence numbers
for (int i = 0; i < SIZE; i++)
{
cout << "Input sequence number: ";
cin >> seq;
buffer[i] = seq;
sum += buffer[i];
}
int UpperBound = sum + 1;
int a = buffer[x] + buffer[x + 1];
int b = buffer[x] + buffer[x + 2];
int c = buffer[x + 1] + buffer[x + 2];
int d = buffer[x] + buffer[x + 1] + buffer[x + 2];
for (int y = IntLowest - 1; y < UpperBound; y++)
{
//How should I proceed from here?
}
return 0;
}
What the answer of Voreno suggests is in fact solving 0-1 knapsack problem (http://en.wikipedia.org/wiki/Knapsack_problem#0.2F1_Knapsack_Problem). If you follow the link you can read how it can be done without constructing all subsets of initial set (there are too much of them, 2^n). And it would work if the constraints were a bit smaller, like 10^3.
But with n = 10^6 it still requires too much time and space. But there is no need to solve knapsack problem - we just need to find first number we can't get.
The better solution would be to sort the numbers and then iterate through them once, finding for each prefix of your array a number x, such that with that prefix you can get all numbers in interval [1..x]. The minimal number that we cannot get at this point is x + 1. When you consider the next number a[i] you have two options:
a[i] <= x + 1, then you can get all numbers up to x + a[i],
a[i] > x + 1, then you cannot get x + 1 and you have your answer.
Example:
you are given numbers 1, 4, 12, 2, 3.
You sort them (and get 1, 2, 3, 4, 12), start with x = 0, consider each element and update x the following way:
1 <= x + 1, so x = 0 + 1 = 1.
2 <= x + 1, so x = 1 + 2 = 3.
3 <= x + 1, so x = 3 + 3 = 6.
4 <= x + 1, so x = 6 + 4 = 10.
12 > x + 1, so we have found the answer and it is x + 1 = 11.
(Edit: fixed off-by-one error, added example.)
I think this can be done in O(n) time and O(log2(n)) memory complexities.
Assuming that a BSR (highest set bit index) (floor(log2(x))) implementation in O(1) is used.
Algorithm:
1 create an array of (log2(MAXINT)) buckets, 20 in case of 10^6, Each bucket contains the sum and min values (init: min = 2^(i+1)-1, sum = 0). (lazy init may be used for small n)
2 one pass over the input, storing each value in the buckets[bsr(x)].
for (x : buffer) // iterate input
buckets[bsr(x)].min = min(buckets[bsr(x)].min, x)
buckets[bsr(x)].sum += x
3 Iterate over buckets, maintaining unreachable:
int unreachable = 1 // 0 is always reachable
for(b : buckets)
if (unreachable >= b.min)
unreachable += b.sum
else
break
return unreachable
This works because, assuming we are at bucket i, lets consider the two cases:
unreachable >= b.min is true: because this bucket contains values in the range [2^i...2^(i+1)-1], this implies that 2^i <= b.min. in turn, b.min <= unreachable. therefor unreachable+b.min >= 2^(i+1). this means that all values in the bucket may be added (after adding b.min all the other values are smaller) i.e. unreachable += b.sum.
unreachable >= b.min is false: this means that b.min (the smallest number the the remaining sequence) is greater than unreachable. thus we need to return unreachable.
The output of the second input is 4 because that is the smallest positive number that cannot be expressed as a sum of 1,2 or 6 if you can take each item only 0 or 1 times. I hope this can help you understand more:
You have 3 items in that list: 1,2,6
Starting from the smallest positive integer, you start checking if that integer can be the result of the sum of 1 or more numbers of the given sequence.
1 = 1+0+0
2 = 0+2+0
3 = 1+2+0
4 cannot be expressed as a result of the sum of one of the items in the list (1,2,6). Thus 4 is the smallest positive integer which cannot be expressed as a sum of the items of that given sequence.
The last output is 4 because:
1 = 1
2 = 2
1 + 2 = 3
1 + 6 = 7
2 + 6 = 8
1 + 2 + 6 = 9
Therefore, the lowest integer that cannot be represented by any combination of your inputs (1, 2, 6) is 4.
What the question is asking:
Part 1. Find the largest possible integer that can be represented by your input numbers (ie. the sum of all the numbers you are given), that gives the upper bound
UpperBound = sum(all_your_inputs) + 1
Part 2. Find all the integers you can get, by combining the different integers you are given. Ie if you are given a, b and c as integers, find:
a + b, a + c, b + c, and a + b + c
Part 2) + the list of integers, gives you all the integers you can get using your numbers.
cycle for each integer from 1 to UpperBound
for i = 1 to UpperBound
if i not = a number in the list from point 2)
i = your smallest integer
break
This is a clumsy way of doing it, but I'm sure that with some maths it's possible to find a better way?
EDIT: Improved solution
//sort your input numbers from smallest to largest
input_numbers = sort(input_numbers)
//create a list of integers that have been tried numbers
tried_ints = //empty list
for each input in input_numbers
//build combinations of sums of this input and any of the previous inputs
//add the combinations to tried_ints, if not tried before
for 1 to input
//check whether there is a gap in tried_ints
if there_is_gap
//stop the program, return the smallest integer
//the first gap number is the smallest integer