Function which increases fast and slows down reaching predefined maximum - algorithm

I am creating a count up algorithm where I increase the number with bigger increments and then the increments get smaller over time, ideally reaching zero or 1. The final sum value should be predefined. The number of steps should be an input parameter and can vary. It seems like it is a logarithmic function with a maximum value. However, the logarithmic function grows until infinity.
The best I've found is square root of logarithm:
val log = (1..10).map { Math.sqrt(Math.log(it * 1.0)) }
val max = log.max()
val rounded = log.map { it * 1000 / max!! }.map { Math.round(it) }
rounded.forEachIndexed { i, l ->
if (i + 1 < rounded.size)
println("${rounded[i + 1] - rounded[i]}")
}
However, i still do not get to very small increments in the end.
If range is from zero to 10:
549, 142, 85, 60, 46, 37, 31, 27, 23
If the range is 20:
481, 125, 74, 53, 40, 33, 27, 23, 21, 18, 16, 14, 14, 12, 11, 10, 10, 9, 9
What algorthm to use to get to 1 in the end?
Update:
Based on Patricks formula I made this solution:
` val N = 18981.0
val log = (1..50).map { N - N/it }
val max = log.max()
log.map { print("$it, ") }
val rounded = log.map { it * N / max!! }.map { Math.round(it) }`
It is important that N is Double and not the whole number

Square root of the logarithm also grows to infinity. Try
f(n) = N - N/n
This has the value 0 at n = 1 and tends towards N as n grows without bound. If you need finer granularity, add some coefficients and play around with them until you get something reasonable. For instance, you can use [1 + (n/1000)] and get similar but much slower growth. You can also use exp(-x) or any function with a horizontal asymptote and get similar behavior.
f(n) = N - exp(-n)
Again, add some coefficients and see how the function changes

Related

Approaching Dynamic Programming problem / Two restrictions

Given an array A of n integers and k <= n, we want to choose k numbers from this array and split them to pairs, such that the sum of the differences of those pairs (in absolute value) is minimal.
Example: If n = 8 and k = 6 and the array is A = [140, 100, 92, 21, 32, 48, 32, 100], then the optimal answer is 27.
Does someone have an idea?
Where do I start from in this problem?
I'm really bad at DP problems, so I would appreciate an informative answer describing the right approach to solve the problem.
Thanks in advance.
Sort elements. Now pairs ought to be made only with neighbors (for cases like 10,20,20,30 pairing 10/20 + 20/30 gives the same result as 10/30 + 20/20, for cases like 10,14,20 pair 10/20 is worse than 10/14 or 14/10)
Walk through array.
If pair is opened with the last element, we have the only possibility - close that pair with current element
If there is no opened pair and number of closed pairs is less than k/2, we have two possibilities - start pair or omit current element (if number of elements in the rest of array is larger than we must use), and we have to choose the best result from these cases.
So we can build recursion and then transform it into DP (code below is not DP yet, it builds full solution tree).
A = [140, 100, 92, 21, 32, 48, 32, 100]
n = len(A)
k = 6
def best(idx, openstate, pairsleft):
if pairsleft > (n - idx + 1)//2:
return 10000000
if pairsleft == 0:
return 0
if openstate:
return abs(A[idx] - A[idx-1]) + best(idx + 1, False, pairsleft - 1)
else:
return(min(best(idx + 1, True, pairsleft), best(idx + 1, False, pairsleft)))
A.sort()
print(best(0, False, k//2))
>> 27

Working through nested loops

Is there a way to find all the primes between 0 to 100 without actually using nested loops, i.e. with time complexity of less than n^2. I did try recursion but it still is same with same complexity. can anyone help please.
Thanks
A very useful implementation is to pre-calculate the list.
my #primes = (
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
);
say for #primes;
Obvious? Maybe, but I bet many people are about to post far more complex, and slower solutions.
Yes, look at the Seive of Atkin, which is an optimized version of the Sieve of Eratosthenes.
Python implementation:
import math
def sieveOfAtkin(limit):
P = [2,3]
sieve=[False]*(limit+1)
for x in range(1,int(math.sqrt(limit))+1):
for y in range(1,int(math.sqrt(limit))+1):
n = 4*x**2 + y**2
if n<=limit and (n%12==1 or n%12==5) : sieve[n] = not sieve[n]
n = 3*x**2+y**2
if n<= limit and n%12==7 : sieve[n] = not sieve[n]
n = 3*x**2 - y**2
if x>y and n<=limit and n%12==11 : sieve[n] = not sieve[n]
for x in range(5,int(math.sqrt(limit))):
if sieve[x]:
for y in range(x**2,limit+1,x**2):
sieve[y] = False
for p in range(5,limit):
if sieve[p] : P.append(p)
return P
print sieveOfAtkin(100)
Not exactly improvement from O(n^2)
But you can narrow down your search like this:
Prime numbers > 6 have a property. They are either 6n+1 or 6n-1(It does not mean that all 6n+1 or 6n-1s are prime numbers)
So your code would look like:
/**
* #author anirbanroy
*/
object PrimeNumberPrinter {
def main(args: Array[String]) {
var count: Int = 0
var initialPrimeNumberCount: Array[Int] = Array(0, 0, 1, 2, 2)
println("Enter a range: ")
val input = io.StdIn.readInt()
if (input > 4) {
count = 2;
for (i <- 5 to input by 6) {
if (i + 2 <= input) {
if (isPrime(i + 2)) {
count = count + 1
}
}
if (i <= input) {
if (isPrime(i)) {
count = count + 1
}
}
}
println("No of prime numbers: " + count)
} else {
println("No of prime numbers are: " + initialPrimeNumberCount(input))
}
}
def isPrime(value: Int): Boolean = {
val range: Int = round(sqrt(value).toFloat)
for (j <- 2 to range) {
if (value.%(j) == 0)
return false
}
return true
}
The brute force solution (trying to divide all odd integers by all odd divisors) doesn't have complexity O(N²), but O(N√N), as the search can stop when a tentative divisor exceeding √N has been reached.
You can pretty easily reduce this complexity by using the primes already identified, rather than all odd integers. Given the density function of the primes, you reduce to O(N√N/Log(N)).
Anyway, for N as small as 100, this "optimization" is not at all significant, as √N is only 10 and the prime divisors to be considered are 3, 5, 7, whereas the odd divisors would be 3, 5, 7, 9.
Here is a simple implementation that tries three divisors and does not attempt to stop when i>√N as this would add costly conditional branches.
N= 100
print 2, 3, 5, 7,
for i in range(3, N, 2):
if i % 3 != 0 and i % 5 != 0 and i % 7 != 0:
print i,
Technically speaking, this code is pure O(N), but only works until N<121. By direct counting, it performs exactly 106 modulo operations when using the shortcut evaluation of the and's.

General algorithm: random sort array, so the distance between objects is maxed

Given an array of random not-unique numbers
[221,44,12,334,63,842,112,12]
What would be the best approach to random sort the values, but also try to max the distance |A-B| to the neighbouring number
You could try a suboptimal greedy algorithm:
1. sortedArr <- sort input array
2. resultArr <- initialize empty array
3. for i=0 to size of sortedArr
a. if i%2
I. resultArr[i] = sortedArr[i/2]
b. else
II. resultArr[i] = sortedArr[sortedArr.size - (i+1)/2]
This puts numbers in the result alternating from the left and right of the sorted input. For example if the sorted input is:
12, 12, 44, 63, 112, 221, 334, 842
Then the output would be:
12, 842, 12, 334, 44, 221, 63, 112
This might not be optimal but it probably gets pretty close and works in O(nlogn). On your example the optimal is obtained by:
63, 221, 12, 334, 12, 842, 44, 112
Which yields a sum of 2707. My algorithm yields a sum of 2656. I'm pretty sure that you won't be able to find the optimal in polynomial time.
A brute force solution in Python would look like:
import itertools
maxSum = 0
maxl = []
for l in itertools.permutations([221,44,12,334,63,842,112,12]):
sum = 0
for i in range(len(l)-1):
sum += abs(l[i]-l[i+1])
if sum > maxSum:
print maxSum
print maxl
maxSum = sum
maxl = l
print maxSum
print maxl

Am I right with this Double Hashing?

I am learning about Double Hash and I got difficulties understanding how it works. I have done an example but I don't know whether it's right or wrong. It would be great if someone can help me.
This is the input:
m = 13
k = { 5, 14, 29, 25, 17, 21, 18, 32, 20, 9, 15, 27 }
h1(k) = k mod 13
h2(k) = 1 + (k mod 11)
That will work as long as m is prime.
Otherwise h2(x) could evaluate to a non-relative-prime of m, which could make the algorithm fail when there is still room for more items.
For example:
m = 36
h1(x) = 1
h2(x) = 30
If table[1], table[31], table[19], table[13], table[7] are all used; Then the next slot that will be checked is table[1] again.
If h2(x) is relatively prime to m, the cycle will always visit all slots before returning to the starting-point. If m is prime, all numbers will be relatively prime.

Two Egg problem confusion

Two Egg problem:
You are given 2 eggs.
You have access to a 100-storey building.
Eggs can be very hard or very fragile means it may break if dropped from the first floor or may not even break if dropped from 100 th floor.Both eggs are identical.
You need to figure out the highest floor of a 100-storey building an egg can be dropped without breaking.
Now the question is how many drops you need to make. You are allowed to break 2 eggs in the process
I am sure the two egg problem ( mentioned above ) has been discussed sufficiently. However could someone help me understand why the following solution is not optimal.
Let's say I use a segment and scan algorithm with the segment size s.
So,
d ( 100 / s + (s-1) ) = 0 [ this should give the minima, I need '(s-1)' scans per segment and there are '100/s' segments]
-
ds
=> -100 / s^2 + 1 = 0
=> s^2 = 100
=> s = 10
So according to this I need at most 19 drops. But the optimal solution can do this with 14 drops.
So where lies the problem?
You seem to be assuming equal-sized segments. For an optimal solution, if the first segment is of size N, then the second has to be of size N-1, and so on (because when you start testing the second segment, you've already dropped the egg once for the first segment).
So you need to solve n+(n-1)+(n-2)+...+1<=100, from where (n)(n+1)/2<=100 (this function transform is done with arithmetic series aka sum of an arithmetic sequence), now if you solve for n (wolframalpha: Reduce[Floor[n + n^2] >= 200, n] ) you get 14. Now you know that the first floor where you need to make the drop is 14th floor, next will be (14+14-1)th floor and whole sequence:
14; 27; 39; 50; 60; 69; 77; 84; 90; 95; 99; 100
If you break the first egg, you go back to the last one and linearly check all options until you break the second egg, when you do, you got your answer. There is no magic.
http://mathworld.wolfram.com/ArithmeticSeries.html
Correct and optimal solution is 13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100 in which average number of trials of finding floor on which egg breaks is minimum, assuming floor on which egg breaks is selected randomly.
Based on this information we can write a recursive function to minimize average trials, that gives a solution of
13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100
It has following max trials for each floor-step
13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14
This is obviously much better than naive solution arrived by assuming gaps starting at 14 and reducing. In this case 55% of time you just need 13 trials. It is very near to optimal solution derived from n (n+1) / 2 >= 100 which gives n = 13.651 and our optimal solution is (13*5+14*9)/14 i.e. 13.643
Here is a quick implementation:
import sys
def get_max_trials(floors):
pf = 0
trials = []
for i, f in enumerate(floors):
trials.append(i+f-pf)
pf = f
return trials
def get_trials_per_floor(floors):
# return list of trials if egg is assumed at each floor
pf = 0
trials = []
for i, f in enumerate(floors):
for mid_f in range(pf+1,f+1):
trial = (i+1) + f - mid_f + 1
if mid_f == pf+1:
trial -= 1
trials.append(trial)
pf = f
return trials
def get_average(floors):
trials = get_trials_per_floor(floors)
score = sum(trials)
return score*1.0/floors[-1], max(trials)
floors_map = {}
def get_floors(N, level=0):
if N == 1:
return [1]
if N in floors_map:
return floors_map[N]
best_floors = None
best_score = None
for i in range(1,N):
base_floors = [f+i for f in get_floors(N-i, level+1)]
for floors in [base_floors, [i] + base_floors]:
score = get_average(floors)
if best_score is None or score < best_score:
best_score = score
best_floors = floors
if N not in floors_map:
floors_map[N] = best_floors
return best_floors
floors = get_floors(100)
print "Solution:",floors
print "max trials",get_max_trials(floors)
print "avg.",get_average(floors)
naive_floors = [14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100]
print "naive_solution",naive_floors
print "max trials",get_max_trials(naive_floors)
print "avg.",get_average(naive_floors)
Output:
Solution: [13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100]
max trials [13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14]
avg. (10.31, 14)
naive_solution [14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100]
max trials [14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12]
avg. (10.35, 14)
I also had the same thought in mind . I was also trying to find the exact method you said . I cleared this solution as explained by one of the members here . But here is a bit more explanation if you might .
N is defined as the minimum no: of searches required .
I am trying to find a no: n such that it is the min no: of searches I have to make .
So I start at xth floor I have 2 scenarios ,
1)
It breaks , I have to do x-1 more checking's (because I have only 1 more egg) . All's fair there . Total is 1+ x-1 = x searches .
Now we have defined this value as n . Hence x = n ! [PS : This might be trivial but this has some subtleties IMO]
2)
It doesnt break - and I have used up one of my n possibilities already !
Now the searches allowed further is n - 1 . Only then the total no: of searches will be N and that is the definition of N .
The problem now has become a sub problem of 100 - n floors with 2 eggs .
If am chosing some yth floor now - its worst case should be n - 1 . (n - 1)th floor satisfies this .
Hence you get the pattern go to nth , n + (n -1 )th floor , n + (n - 1) + (n - 2)th floor .... Solve this for 100th floor and you get N .
The floor you start with and the no: of searches is a coincidence I think .
To get the maxima n = 14 , you can think of having n bulbs with 2 bulbs glowing at once .
It will require atleast 14 bulbs to cover all the possible combinations of where egg can break .
As a challenge try to do it for 3 eggs .
In your logic basically , there is an asymmetry in how the search progress .
For the first set of 10 elements , the algorithm finds out quickly .
I would suggest to try and check
http://ite.pubs.informs.org/Vol4No1/Sniedovich/ for some explnation and also try to visualize how this problem is seen in real cases of Networks .
A very nice explanation of the solution I found in the below link.
The Two Egg Problem
It explains how you get to n+(n-1)+(n-2)+...+1<=100
The 1 Egg Problem - Linear Complexity O(100)
and Multiple(Infinite) Eggs Problem - Logarithmic complexity O(log2(100)).
Here's a solution in Python. If you drop the egg at a certain floor f, it either breaks or it doesn't, and in each case you have a certain number of floors you still need to check (which is a subproblem). It uses a recursion and also a lookup dictionary to make it much faster to compute.
neededDict = {}
# number of drops you need to make
def needed(eggs, floors):
if (eggs, floors) in neededDict:
return neededDict[(eggs, floors)]
if eggs == 1:
return floors
if eggs > 1:
minimum = floors
for f in range(floors):
#print f
resultIfEggBreaks = needed(eggs - 1, f)
resultIfEggSurvives = needed(eggs, floors - (f + 1))
result = max(resultIfEggBreaks, resultIfEggSurvives)
if result < minimum:
minimum = result
# 1 drop at best level f plus however many you need to handle all floors that remain unknown
neededDict[(eggs, floors)] = 1 + minimum
return 1 + minimum
print needed(2, 100)
The question should not be how many drops you need to make ? but rather than that it should be find the minimal number of drops in order to know where the egg breaks, I saw this issue on careercup, below is the algorithms I thought of:
There are two ways to solve this problem :
binary search for the first egg (risked to know where we need to look
up) O(binary log)
Fibonaccy sequence search 1,2,3,5,8,13,21,34,55,89 for the first egg O(log) http://en.wikipedia.org/wiki/Fibonacci_search_technique
Once first egg is broken we know in which interval we need to look:
binary example:
we try 100/2 (50) if it broke we search from 1 to 50 incrementing by 1 if not we throw it from 50+100/2 (75) if it broke we search from 50 to 75 if not we throw it from 75+100/2 (87) if it broke we search from 75 to 87 incemrenting by one floor at a time and so on and so forth.
fibonacy example: same thing : we try 1,2,3,5,8.13,... if first egg
broke we get back to the last interval's minimum and increment by 1.
hey what about this approach.
Try this sequence:
1,2,4,8,16,32,64,100
And once you find the egg is broken you well get a space to work on.
lets suppose # 64 egg breaks. then the answer lies between 32 & 64.
We can use normal binary search between those 2 number.
we will check # 48 (32+64)/2 and then we will get the upper half or lower half as shortlisted space. and repeat
In this case the worst case is having the floor at 99. which will take 14 tries.
The explanation of the two eggs problem can make some people confused in the first time, so we can understand the solution as follows:
Given x is the floor we start dropping the eggs:
- If it breaks, the total of trials in the worst case is x + (x - 1)
- If it doesn't break, how should we step up to the next floor? We can jump to floor (x + x)th, (x + x + 1)th... But it will increase the number of trials, we can try at x = 10:
. If it does break, we must try 10 times total in the worst case.
. If it does not break, and we step up to 10th + 10th = 20th and try, and if it breaks, we must try 1 (at floor 10th) + 1 (at floor 20th) + 9 = 11 times. Similarly, if we step up to x + 1, or x + 2 floor it will increase the number of trials.
Actually, we want the number of trials being equal in both cases, for that reason we will step up to x - 1 floor instead of x, x + 1.,etc. Finally, we will have an expression in general:
x + (x - 1) + (x - 2) + ... + 1.
And that's it.
I would say the optimal solution for 100 floors with two eggs is 13 tries not 14.
13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100 is the optimal answer, but if I reach to 99 I do not really need to try out 100. It is obvious the correct answer without try to drop egg from 100th floor :D

Resources