Facebook interview: find out the order that gives max sum by selecting boxes with number in a ring, when the two next to it is destroyed - facebook

Didn't find any similar question about this.
This is a final round Facebook question:
You are given a ring of boxes. Each box has a non-negative number on it, can be duplicate.
Write a function/algorithm that will tell you the order at which you select the boxes, that will give you the max sum.
The catch is, if you select a box, it is taken off the ring, and so are the two boxes next to it (to the right and the left of the one you selected).
so if I have a ring of
{10 3 8 12}
If I select 12, 8 and 10 will be destroyed and you are left with 3.
The max will be selecting 8 first then 10, or 10 first then 8.
I tried re-assign the boxes their value by take its own value and then subtracts the two next to is as the cost.
So the old ring is {10 3 8 12}
the new ring is {-5, -15, -7, -6}, and I will pick the highest.
However, this definitely doesn't work if you have { 10, 19, 10, 0}, you should take the two 10s, but the algorithm will take the 19 and 0.
Help please?
It is most likely dynamic programming, but I don't know how.
The ring can be any size.

Here's some python that solves the problem:
def sublist(i,l):
if i == 0:
return l[2:-1]
elif i == len(l)-1:
return l[1:-2]
else:
return l[0:i-1] + l[i+2:]
def val(l):
if len(l) <= 3:
return max(l)
else:
return max([v+val(m) for v,m in [(l[u],sublist(u,l)) for u in range(len(l))]])
def print_indices(l):
print("Total:",val(l))
while l:
vals = [v+val(m) for v,m in [(l[u],sublist(u,l)) for u in range(len(l)) if sublist(u,l)]]
if vals:
i = vals.index(max(vals))
else:
i = l.index(max(l))
print('choice:',l[i],'index:',i,'new list:',sublist(i,l))
l = sublist(i,l)
print_indices([10,3,8,12])
print_indices([10,19,10,0])
Output:
Total: 18
choice: 10 index: 0 new list: [8]
choice: 8 index: 0 new list: []
Total: 20
choice: 10 index: 0 new list: [10]
choice: 10 index: 0 new list: []
No doubt it could be optimized a bit. The key bit is val(), which calculates the total value of a given ring. The rest is just bookkeeping.

Related

numbered. Find the prime number n

There were a lot of people in our contest today, we numbered each of them separately, ie the first person 2, the second person 3, etc. In this order, 5, 7, 11, 13,… you understood the sequence.
Your task is to find the number of the N-person.
For example: User enters the value of N = 3.
Desired output: 5
The length of the value entered by the user is 10^9
The code I wrote. this number cannot be deduced
import math
def is_prime(n, div=2):
if div> int(math.sqrt(n)): return True
if n% div == 0:
return False
else:
div+=1
return is_prime(n,div)
a =int(input())
if a == 1:
print('2')
else:
primelist=[]
i=1;
while len(primelist)<999:
if is_prime(i):
primelist.insert(0,i)
i+=1
else: i+=1
print(primelist[-a-1])
Kindly advise.

How to round integer number using precision in flutter

I am trying to make the Y axis intervals of linechart dynamic in flutter. Here the MaxVal will get the maximum value of the Y axis.
int interval = (maxVal/6).toInt();
int length = interval.toString().length.toInt();
So here I have divided the maxVal with 6 so I will get the interval and I will find out the length. Next I need to round the interval according to the length. But I couldn't see any option to add precision for in flutter.
The Expected Output
If maxVal = 10000 then
interval will 1666
then length will 4. Then
I expected rounded value will be 2000
I'm assuming that you're asking to round a (non-negative) integer to its most significant base-10 digit. A general way to round non-negative integers is to add half of the unit you want to round to and to then truncate. For example, if you want to round a non-negative integer to the nearest 1000, you can add 1000/2 = 500, and then discard the hundreds, tens, and ones digits. An easy way to discard those digits is to perform an integer division by 1000 and then to multiply by 1000 again.
The trickiest part is determining what unit you want to round to since that's variable. If you want the most significant base-10 digit, you will need to determine the number of digits. In theory you can compute that with logarithms, but it's usually risky to depend on exact results with floating-point arithmetic, you'd have to deal with 0 as a special case, and it's harder to be confident of correctness. It's simpler and less error-prone to just find the length of the number's string representation. Once we find the number of digits, we can determine which unit to round to computing a corresponding power of 10.
import 'dart:math';
/// Rounds [n] to the nearest multiple of [multiple].
int roundToMultiple(int n, int multiple) {
assert(n >= 0);
assert(multiple > 0);
return (n + (multiple ~/ 2)) ~/ multiple * multiple;
}
/// Rounds [n] to its most significant digit.
int roundToMostSignificantDigit(int n) {
assert(n >= 0);
var numDigits = n.toString().length;
var magnitude = pow(10, numDigits - 1) as int;
return roundToMultiple(n, magnitude);
}
void main() {
var inputs = [
0,
1,
5,
9,
10,
11,
16,
19,
20,
21,
49,
50,
51,
99,
100,
469,
833,
1666,
];
for (var n in inputs) {
var rounded = roundToMostSignificantDigit(n);
print('$n => $rounded');
}
}
which prints:
0 => 0
1 => 1
5 => 5
9 => 9
10 => 10
11 => 10
16 => 20
19 => 20
20 => 20
21 => 20
49 => 50
50 => 50
51 => 50
99 => 100
100 => 100
469 => 500
833 => 800
1666 => 2000
(The above code should be tweakable to handle negative numbers too if desired, but first you would need to define whether negative numbers should be rounded toward 0 or toward negative infinity.)

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".

Creating an optimal selection of overlapping time intervals

A car dealer rents out the rare 1956 Aston Martin DBR1 (of which Aston Martin only ever made 5).
Since there are so many rental requests, the dealer decides to place bookings for an entire year in advance.
He collects the requests and now needs to figure out which requests to take.
Make a script that selects the rental requests such that greatest number of individual customers
can drive in the rare Aston Martin.
The input of the script is a matrix of days of the year, each row representing the starting and ending
days of the request. The output should be the indices of the customers and their day ranges.
It is encouraged to plan your code first and write your own functions.
At the top of the script, add a comment block with a description of how your code works.
Example of a list with these time intervals:
list = [10 20; 9 15; 16 17; 21 100;];
(It should also work for a list with 100 time intervals)
We could select customers 1 and 4, but then 2 and 3 are impossible, resulting in two happy customers.
Alternatively we could select requests 2, 3 and 4. Hence three happy customers is the optimum here.
The output would be:
customers = [2, 3, 4],
days = [9, 15; 16, 17; 21, 100]
All I can think of is checking if intervals intersect, but I have no clue how to make an overall optimal selection.
My idea:
1) Sort them by start date
2) Make an array of intersections for each one
3) Start to reject from the ones which has the biggest intersection array, removing rejected item from arrays of intersected units
4) Repeat point 3 until only units with empty arrays will remain
In your example we will get data
10 20 [9 15, 16 17]
9 15 [10 20]
16 17 [10 20]
21 100 []
so we reject 10 20 as it has 2 intersections, so we will have only items with empty arrays
9 15 []
16 17 []
21 100 []
so the search is finished
code on javascript
const inputData = ' 50 74; 6 34; 147 162; 120 127; 98 127; 120 136; 53 68; 145 166; 95 106; 242 243; 222 250; 204 207; 69 79; 183 187; 198 201; 184 199; 223 245; 264 291; 100 121; 61 61; 232 247'
// convert string to array of objects
const orders = inputData.split(';')
.map((v, index) => (
{
id: index,
start: Number(v.split(' ')[1]),
end: Number(v.split(' ')[2]),
intersections: []
}
))
// sort them by start value
orders.sort((a, b) => a.start - b.start)
// find intersection for each one and add them to intersection array
orders.forEach((item, index) => {
for (let i = index + 1; i < orders.length; i++) {
if (orders[i].start <= item.end) {
item.intersections.push(orders[i])
orders[i].intersections.push(item)
} else {
break
}
}
})
// sort by intersections count
orders.sort((a, b) => a.intersections.length - b.intersections.length)
// loop while at least one item still has intersections
while (orders[orders.length - 1].intersections.length > 0) {
const rejected = orders.pop()
// remove rejected item from other's intersections
rejected.intersections.forEach(item => {
item.intersections = item.intersections.filter(
item => item.id !== rejected.id
)
})
// sort by intersections count
orders.sort((a, b) => a.intersections.length - b.intersections.length)
}
// sort by start value
orders.sort((a, b) => a.start - b.start)
// show result
orders.forEach(item => { console.log(item.start + ' - ' + item.end)})
Wanted to expand/correct a little bit on the acvepted answer.
You should start by sorting by the start date.
Then accept the very last customer.
Go through the list descending from there and accept all request that do not overlap with the already accepted ones.
That's the optimal solution.

How to check if a number can be represented as a sum of some given 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