How to check if a number can be represented as a sum of some given numbers - numbers

I've got a list of some integers, e.g. [1, 2, 3, 4, 5, 10]
And I've another integer (N). For example, N = 19.
I want to check if my integer can be represented as a sum of any amount of numbers in my list:
19 = 10 + 5 + 4
or
19 = 10 + 4 + 3 + 2
Every number from the list can be used only once. N can raise up to 2 thousand or more. Size of the list can reach 200 integers.
Is there a good way to solve this problem?

4 years and a half later, this question is answered by Jonathan.
I want to post two implementations (bruteforce and Jonathan's) in Python and their performance comparison.
def check_sum_bruteforce(numbers, n):
# This bruteforce approach can be improved (for some cases) by
# returning True as soon as the needed sum is found;
sums = []
for number in numbers:
for sum_ in sums[:]:
sums.append(sum_ + number)
sums.append(number)
return n in sums
def check_sum_optimized(numbers, n):
sums1, sums2 = [], []
numbers1 = numbers[:len(numbers) // 2]
numbers2 = numbers[len(numbers) // 2:]
for sums, numbers_ in ((sums1, numbers1), (sums2, numbers2)):
for number in numbers_:
for sum_ in sums[:]:
sums.append(sum_ + number)
sums.append(number)
for sum_ in sums1:
if n - sum_ in sums2:
return True
return False
assert check_sum_bruteforce([1, 2, 3, 4, 5, 10], 19)
assert check_sum_optimized([1, 2, 3, 4, 5, 10], 19)
import timeit
print(
"Bruteforce approach (10000 times):",
timeit.timeit(
'check_sum_bruteforce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 200)',
number=10000,
globals=globals()
)
)
print(
"Optimized approach by Jonathan (10000 times):",
timeit.timeit(
'check_sum_optimized([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 200)',
number=10000,
globals=globals()
)
)
Output (the float numbers are seconds):
Bruteforce approach (10000 times): 1.830944365834205
Optimized approach by Jonathan (10000 times): 0.34162875449254027

The brute force approach requires generating 2^(array_size)-1 subsets to be summed and compared against target N.
The run time can be dramatically improved by simply splitting the problem in two. Store, in sets, all of the possible sums for one half of the array and the other half separately. It can now be determined by checking for every number n in one set if the complementN-n exists in the other set.
This optimization brings the complexity down to approximately: 2^(array_size/2)-1+2^(array_size/2)-1=2^(array_size/2 + 1)-2
Half of the original.
Here is a c++ implementation using this idea.
#include <bits/stdc++.h>
using namespace std;
bool sum_search(vector<int> myarray, int N) {
//values for splitting the array in two
int right=myarray.size()-1,middle=(myarray.size()-1)/2;
set<int> all_possible_sums1,all_possible_sums2;
//iterate over the first half of the array
for(int i=0;i<middle;i++) {
//buffer set that will hold new possible sums
set<int> buffer_set;
//every value currently in the set is used to make new possible sums
for(set<int>::iterator set_iterator=all_possible_sums1.begin();set_iterator!=all_possible_sums1.end();set_iterator++)
buffer_set.insert(myarray[i]+*set_iterator);
all_possible_sums1.insert(myarray[i]);
//transfer buffer into the main set
for(set<int>::iterator set_iterator=buffer_set.begin();set_iterator!=buffer_set.end();set_iterator++)
all_possible_sums1.insert(*set_iterator);
}
//iterator over the second half of the array
for(int i=middle;i<right+1;i++) {
set<int> buffer_set;
for(set<int>::iterator set_iterator=all_possible_sums2.begin();set_iterator!=all_possible_sums2.end();set_iterator++)
buffer_set.insert(myarray[i]+*set_iterator);
all_possible_sums2.insert(myarray[i]);
for(set<int>::iterator set_iterator=buffer_set.begin();set_iterator!=buffer_set.end();set_iterator++)
all_possible_sums2.insert(*set_iterator);
}
//for every element in the first set, check if the the second set has the complemenent to make N
for(set<int>::iterator set_iterator=all_possible_sums1.begin();set_iterator!=all_possible_sums1.end();set_iterator++)
if(all_possible_sums2.find(N-*set_iterator)!=all_possible_sums2.end())
return true;
return false;
}

Ugly and brute force approach:
a = [1, 2, 3, 4, 5, 10]
b = []
a.size.times do |c|
b << a.combination(c).select{|d| d.reduce(&:+) == 19 }
end
puts b.flatten(1).inspect

Related

It is necessary to organize the registration of clients in the solarium

I have a task that I have not been able to solve for several weeks.
It is necessary to arrange the registration of clients in the solarium, which has S free booths. This means that there cannot be more than S people in the solarium at the same time. The duration of the stay is the same for everyone and is equal to T. At the input, we get an array with the recording time for each new client.
For example:
1, 3, 5, 1, 8, 5, 0, 6
S = 2
T = 3
This means that the first client wants to come from 1 to 4, the second from 3 to 6, etc. For each of them we have to output YES or NO, depending on whether there are free seats. For the example above, we will output YES YES YES NO YES NO YES YES.
Drawing for the first example
Another example:
1, 9, 0, 7, 2, 7, 6, 4, 10, 5
S = 3
T = 4
YES YES YES YES YES YES NO YES NO NO
N, S, T (1 ≤ N, S ≤ 200 000, 1 ≤ T ≤ 1 000 000).
Maximum array length = 1 000 000
Here is an example of my solution in Swift.
I run through all the time intervals, starting from the second one, and for each one I check the number of intersections with the rest. If there are 2 intersections, I output YES, otherwise NO.
But this solution does not work correctly on the last segments, since they, among other things, also intersect with each other.
let numberOfRequest = 8
let maxPeople = 2
let maxTime = 3
var kab = 0
let timeOfRequests = [1, 3, 5, 1, 8, 5, 0, 6]
var result = [(Int, Int)]()
for i in timeOfRequests {
result.append((i, i + maxTime))
}
print("Yes")
for i in 1..<result.count {
kab = 0
for j in 0..<i {
if max(result[i].0, result[j].0) < min(result[i].1, result[j].1) {
kab += 1
}
}
if kab < 2 {
print("Yes")
} else {
print("No")
result[i] = (0, 0)
}
}
Output: Yes Yes Yes No Yes No Yes No

Best way to find the largest amount of consecutive integers in a sorted array in swift, preferably not using a for loop

Given an array of integers for example let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
What is the best way of finding the largest amount of consecutive integers preferably without using a for-in loop. If we would pass this array into a function it would return 3 as '7, 8, 9' is the largest amount of consecutive integers.
let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
func getMaxConsecutives(from array: [Int]) -> Int {
var maxCount = 1
var tempMaxCount = 1
var currentNumber = array[0]
for number in array {
if currentNumber == number - 1 {
tempMaxCount += 1
maxCount = tempMaxCount > maxCount ? tempMaxCount : maxCount
currentNumber = number
} else {
tempMaxCount = 1
currentNumber = number
}
}
return maxCount
}
getMaxConsecutives(from: array)
This works as intended but I would like a more efficient solution something that is not O(n).
I appreciate any creative answers.
You can do it like this:
let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
if let maxCount = IndexSet(array).rangeView.max(by: {$0.count < $1.count})?.count {
print("The largest amount of consecutive integers: \(maxCount)")
//prints 3
}
I think I can write it more tightly (basically as a one-liner):
let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
let (_,_,result) = array.reduce((-1000,1,0)) {
$1 == $0.0+1 ? ($1,$0.1+1,max($0.2,$0.1+1)) : ($1,1,$0.2)
}
print(result) // 3
But we are still looping through the entire array — so that we are O(n) — and there is no way to avoid that. After all, think about what your eye does as it scans the array looking for the answer: it scans the whole array.
(One way to achieve some savings: You could short-circuit the loop when we are not in the middle of a run and the maximum run so far is longer than what remains of the array! But the gain might not be significant.)

Python: add zeroes in single digit numbers without using .zfill

Im currently using micropython and it does not have the .zfill method.
What Im trying to get is to get the YYMMDDhhmmss of the UTC.
The time that it gives me for example is
t = (2019, 10, 11, 3, 40, 8, 686538, None)
I'm able to access the ones that I need by using t[:6]. Now the problem is with the single digit numbers, the 3 and 8. I was able to get it to show 1910113408, but I need to get 19101034008 I would need to get the zeroes before those 2. I used
t = "".join(map(str,t))
t = t[2:]
So my idea was to iterate over t and then check if the number is less than 10. If it is. I will add zeroes in front of it, replacing the number . And this is what I came up with.
t = (2019, 1, 1, 2, 40, 0)
t = list(t)
for i in t:
if t[i] < 10:
t[i] = 0+t[i]
t[i] = t[i]
print(t)
However, this gives me IndexError: list index out of range
Please help, I'm pretty new to coding/python.
When you use
for i in t:
i is not index, each item.
>>> for i in t:
... print(i)
...
2019
10
11
3
40
8
686538
None
If you want to use index, do like following:
>>> for i, v in enumerate(t):
... print("{} is {}".format(i,v))
...
0 is 2019
1 is 10
2 is 11
3 is 3
4 is 40
5 is 8
6 is 686538
7 is None
another way to create '191011034008'
>>> t = (2019, 10, 11, 3, 40, 8, 686538, None)
>>> "".join(map(lambda x: "%02d" % x, t[:6]))
'20191011034008'
>>> "".join(map(lambda x: "%02d" % x, t[:6]))[2:]
'191011034008'
note that:
%02d add leading zero when argument is lower than 10 otherwise (greater or equal 10) use itself. So year is still 4digit string.
This lambda does not expect that argument is None.
I tested this code at https://micropython.org/unicorn/
edited :
str.format method version:
"".join(map(lambda x: "{:02d}".format(x), t[:6]))[2:]
or
"".join(map(lambda x: "{0:02d}".format(x), t[:6]))[2:]
second example's 0 is parameter index.
You can use parameter index if you want to specify it (ex: position mismatch between format-string and params, want to write same parameter multiple times...and so on) .
>>> print("arg 0: {0}, arg 2: {2}, arg 1: {1}, arg 0 again: {0}".format(1, 11, 111))
arg 0: 1, arg 2: 111, arg 1: 11, arg 0 again: 1
I'd recommend you to use Python's string formatting syntax.
>> t = (2019, 10, 11, 3, 40, 8, 686538, None)
>> r = ("%d%02d%02d%02d%02d%02d" % t[:-2])[2:]
>> print(r)
191011034008
Let's see what's going on here:
%d means "display a number"
%2d means "display a number, at least 2 digits"
%02d means "display a number, at least 2 digits, pad with zeroes"
so we're feeding all the relevant numbers, padding them as needed, and cut the "20" out of "2019".

For the series 1, 1, 2, 2, 4, 2, 6, what are the next terms in the sequence? What is the nth term?

i want to know the pattern for the above series in order to write the code for above series.
I am thinking that the above series is mix of two different series 1,2,4,6,...and 1,2,2,..
Please help me with this sequence and also tell whether i am thinking in correct way or not.
logic :--
series 1-> Prime-1 i.e. [1, 2, 4, 6, 10, 12, 16, 18, 22, 28, 30, 36.....]
series 2-> Number Series i.e. [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5.....]
final output -> Alternate Series i.e. [1 1 2 2 4 2 6 3 10 3 12 3 16 4 18 4 22 4 28 4....]
Note : There might be another logic but by the given Question, this series can be identified by below program..
Please do not use for any competition Test/Exam
import math
global li_prime;global li_series;xp=0
def prime(size):
global li_prime;count = 2;
while len(li_prime)
isprime = True
for x in range(2, int(math.sqrt(count) + 1)):
if count % x == 0:
isprime = False
break
if isprime:
li_prime.append(count-1)
count += 1
def series(size):
global li_series
for i in range(size+1):
for j in range(i):
li_series.append(i)
if len(li_series)>size:
break
def main():
global xp
global li_prime
global li_series
testcase=int(input(''))
for I in range(testcase):
li_series=[]
li_prime=[]
size=int(input(''))
prime(size)
series(size)
li_prime=li_prime[:size]
li_series=li_series[:size]
lc=[]
for i in range(size//2+1):
lc.append(str(li_prime[i]))
lc.append(str(li_series[i]))
lc=lc[:size]
main()
It is series whose greatest common divisior (gcd) is 1 also known as Euler's Totient Function.
series format = {1 1 2 2 4 2 6 32 ..... 168 80 216 120 164 100}
Code:
public static void main(String[] args) {
//n is the input for the size of the series
for(int j=1;j<=n;j++){
System.out.print(calSeriesVal(j)+" ");
}
}
private static int calDivisor(int a, int b)
{
if (a == 0)
return b;
return calDivisor(b % a, a);
}
private static int calSeriesVal(int n)
{
int val = 1;
for (int i = 2; i < n; i++)
if (calDivisor(i, n) == 1)
val++;
return val;
}

Merging two sorted lists, one with additional 0s

Consider the following problem:
We are given two arrays A and B such that A and B are sorted
except A has B.length additional 0s appended to its end. For instance, A and B could be the following:
A = [2, 4, 6, 7, 0, 0, 0]
B = [1, 7, 9]
Our goal is to create one sorted list by inserting each entry of B
into A in place. For instance, running the algorithm on the above
example would leave
A = [1, 2, 4, 6, 7, 7, 9]
Is there a clever way to do this in better than O(n^2) time? The only way I could think of is to insert each element of B into A by scanning linearly and performing the appropriate number of shifts, but this leads to the O(n^2) solution.
Some pseudo-code (sorta C-ish), assuming array indexing is 0-based:
pA = A + len(A) - 1;
pC = pA; // last element in A
while (! *pA) --pA; // find the last non-zero entry in A
pB = B + len(B) - 1;
while (pA >= A) && (pB >= B)
if *pA > *pB
*pC = *pA; --pA;
else
*pC = *pB; --pB;
--pC
while (pB >= B) // still some bits in B to copy over
*pC = *pB; --pB; --pC;
Not really tested, and just written off the top of my head, but it should give you the idea... May not have the termination and boundary conditions exactly right.
You can do it in O(n).
Work from the end, moving the largest element towards the end of A. This way you avoid a lot of trouble to do with where to keep the elements while iterating. This is pretty easy to implement:
int indexA = A.Length - B.Length - 1;
int indexB = B.Length - 1;
int insertAt = A.Length;
while (indexA > 0 || indexB > 0)
{
insertAt--;
A[insertAt] = max(B[indexB], A[indexA]);
if (A[indexA] <= B[indexB])
indexB--;
else
indexA--;
}