I was asked this in an interview.
I was asked to compute the average of numbers x1,x2,x3,...xn
class Iterator {
bool hasNext;
int getNext();
}
// So it came down to something like this:
double average (Iterator & it) {
double average = 0;
double sum = 0;
int len = 0;
while (it.hasNext == true) {
sum += it.getNext();
}
if (len > 0)
average = sum / len;
}
The interviewer said the list size is unkown and it can be very big, so sum can overflow. He asked how do I solve the overflow problem, I answered by keeping track of how may times we exceed the max number and so forth, he said something about pushing into stack, the average and length, I never really understood his solution by pushing these 2 variables into some sort of list? Anyone has a clue?
I don't know about using a stack, but with some help from algebra, we can derive a formula for the new average, using the old average.
Let's say you have already averaged n - 1 items, and you have that average in oldAvg.
oldAvg = (x1 + x2 + .. + xn - 1) / (n - 1)
The new average would be represented by newAvg:
newAvg = (x1 + x2 + .. + xn - 1 + xn) / n
With some algebraic manipulation, we can represent the new average using the old average the number of items averaged, and the next item.
newAvg = (x1 + x2 + .. + xn - 1) / n + xn / n
= ((n - 1)/(n - 1)) * (x1 + x2 + .. + xn - 1) / n + xn / n
= oldAvg / n * (n - 1) + xn / n
This can avoid overflow by dividing by n before multiplying by n - 1. Then all you have to do is add in the next item, xn, divided by n.
The first loop would establish the average as equal to the first element, but each subsequent loop would use the formula above to derive the new average.
n++;
newAvg = oldAvg / n * (n - 1) + it.next() / n;
He was probably referring to the fact that you don't need all the terms to compute an average, you can instead keep track of a moving average. That can be used along with the number of terms so far considered to come up with the sum of the terms.
Since the total could be too large to store as a long, you'd want to use something like a BigInteger to hold the total.
If you simplify rgettman's formula further you will get following:
len++;
average = average + (it.next() - average) / len;
Related
I have a below method which iterates a distance array and divide each element by a number starting with 1 and get the sum. If sum is greater than value points which is passed to the method then start again in the for loop and divide by 2 and keep going until you find a sum which is less than value points.
Below code works but is there any way to write this better?
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
int c = 1;
while (true) {
for (Integer dist : distance) {
sum = (int) (sum + Math.ceil(dist / c));
}
if (sum <= points) {
break;
}
c++;
sum = 0;
}
return c;
}
If there is no specific reason to do Math.ceil to each ratio rather than to the final sum, you can just get the sum of all elements first and then find the value of c
sum / c <= points
sum / points <= c
if 0 < (sum / points) < 1, c = 1
else c = Math.ceil(sum / points)
public static int findMin(List<Integer> distance, int points) {
AtomicInteger c = new AtomicInteger(1);
while (distance.stream().mapToInt(d -> d / c.get()).sum() > points) c.incrementAndGet();
return c.get();
}
Correct me if I'm wrong but assuming the set of distances is [1, 2, 3] right? Then you start with 1/1 + 2/1 + 3/1 which (let's leave them as fractions here) equals 6/1, since they all have the same "denominator" here, it doesn't change. So that means that the first iteration, dividing by one, is literally the sum of the values. (1 + 2 + 3) / 1 divided by one. And anything divided by 1 is itself. So it's just the sum.
Now. On the second pass, if I assume correctly, 1/2 + 2/2 + 3/2 -- again leaving them as fractions -- (1 + 2 + 3) / 2 = 6/2. By now you should see a pattern, right? First pass was 6/1 second is 6/2 next will be 6/3...
So how about:
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
for (Integer i : distance) {
sum += i;
}
int min = 1;
while (sum / min > points) {
min += 1;
}
return min;
}
Perhaps a solution like this would work?
edit So as it turns out this solution is assuming (at least partially) some mathematical accuracy, however it appears that the division per-element is required to be integer division which skews some of the results if we approach it strictly mathematically. So while not being a direct answer to the problem I feel like it's correct enough to leave here as a solution.
I think,we can do two things to improve the performance,but the method is not the best and it depend on the number of your list:
reduce the times of iterate
use greedy algorithm priority reduction the max value. In order to do this we first need to sort the list it cost may cost O(nlog(n)) time.
code like this
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
int c = 1;
// sort the list for implement greedy algorithm
Collections.sort(distance, Comparator.reverseOrder());
while (true) {
for (Integer dist : distance) {
sum += dist / c;
// reduce the times of iterate
if (sum <= points) {
return c;
}
}
c++;
sum = 0;
}
}
How do I map numbers, linearly, between a and b to go between c and d.
That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.
My brain is fried.
If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
Y = (X-A)/(B-A) * (D-C) + C
That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.
Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
This evenly spreads the numbers from the first range in the second range.
It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages.
Here is a simple implementation:
final static double EPSILON = 1e-12;
public static double map(double valueCoord1,
double startCoord1, double endCoord1,
double startCoord2, double endCoord2) {
if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
throw new ArithmeticException("/ 0");
}
double offset = startCoord2;
double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
return ratio * (valueCoord1 - startCoord1) + offset;
}
I am putting this code here as a reference for future myself and may be it will help someone.
As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
In addition to #PeterAllenWebb answer, if you would like to reverse back the result use the following:
reverseX = (B-A)*(Y-C)/(D-C) + A
Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
How you handle the rounding is up to you.
if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map
use this formula (linear mapping)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Where X is the number to map from A-B to C-D, and Y is the result:
Take the linear interpolation formula, lerp(a,b,m)=a+(m*(b-a)), and put C and D in place of a and b to get Y=C+(m*(D-C)). Then, in place of m, put (X-A)/(B-A) to get Y=C+(((X-A)/(B-A))*(D-C)). This is an okay map function, but it can be simplified. Take the (D-C) piece, and put it inside the dividend to get Y=C+(((X-A)*(D-C))/(B-A)). This gives us another piece we can simplify, (X-A)*(D-C), which equates to (X*D)-(X*C)-(A*D)+(A*C). Pop that in, and you get Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A)). The next thing you need to do is add in the +C bit. To do that, you multiply C by (B-A) to get ((B*C)-(A*C)), and move it into the dividend to get Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A)). This is redundant, containing both a +(A*C) and a -(A*C), which cancel each other out. Remove them, and you get a final result of: Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
TL;DR: The standard map function, Y=C+(((X-A)/(B-A))*(D-C)), can be simplified down to Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;
int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;
println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
stepF += rate;
println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);
With checks on divide by zero, of course.
I have been trying to solve QuickSort and I got thru a scenario where we are selecting pivot element as the middle one.
http://www.java2novice.com/java-sorting-algorithms/quick-sort/
// calculate pivot number, I am taking pivot as middle index number
int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
How difference this is with the below way to get the middle index?
int pivot = array[(lowerIndex+higherIndex)/2];
I remember I have seen this many times before also. And I am sure I am missing a scenario where this helpful when we get a odd number or something.
I tried few sample values but I get the same response for both ways.
What am I missing?
Thanks for your respone.
It is more likely that
(lowerIndex+higherIndex)/2
overflows rather than
lowerIndex+(higherIndex-lowerIndex)/2.
For example for lowerIndex == higherIndex == Integer.MAX_VALUE / 2 + 1.
Edit:
Mathematical proof of equivalence of the expressions
l + (r - l)/2 (in java notation)
= l + round_towards_zero((r - l) / 2) (in math notation)
= round_towards_zero(l + (r - l) / 2) (since l is an integer)
= round_towards_zero((2 * l + r - l) / 2)
= round_towards_zero(r + l) / 2)
= (l + r) / 2 (in java notation)
I have this algorithm that works, but I want to change it to have a dynamic ratio in order to have the distance of values for the first positions higher than those ones for the lastest positions.
So for instance if prize money = 1000, total_prizes = 5, last_prize = 50 I got:
1) 350.00
2) 275.00
3) 200.00
4) 125.00
5) 50.00
TOTAL SUM: 1000.00
What I would like to see should be:
1) 475.00
2) 250.00
3) 150.00
4) 75.00
5) 50.00
TOTAL SUM: 1000.00
Instead of having between positions always a fixed value of 75. Have an increase distance approaching the first positions, in this case
from 5) to 4) 25
from 4) to 3) 75
from 3) to 2) 100
from 2) to 1) 225
Here the current code:
public static void main(String[] aa){
float ratio;
float first_prize;
float s=0;
float money = 1000;
int total_prizes = 5;
float last_prize = 50;
float prizes[] = new float[total_prizes+1];
first_prize=2*(money/total_prizes)-last_prize; //last member of the progresion
ratio=(first_prize-last_prize)/(total_prizes-1);
prizes[total_prizes]=last_prize;
for (int j = total_prizes-1; j >=1; j--) {
prizes[j]=prizes[j+1]+ratio;
}
for(int k=1;k<=total_prizes;k++){
System.out.printf("%d) %.2f\n",k,prizes[k]);
s+=prizes[k];
}
System.out.printf("TOTAL SUM: %.2f\n",s);
}
Inside the loop:
for (int j = total_prizes-1; j >=1; j--) {
//ratio here should be calculated dynamically based on position...
prizes[j]=prizes[j+1]+ratio;
}
Thanks! :)
If I understand you, what you want is to have the following conditions:
Fixed total sum. In this case 1000.
Approximately a geometric ratio r with n terms. In this case 1.75.
All "round" numbers. In this case to the nearest 25.
I would suggest that you solve it by first creating an exact geometric sequence, and then tweak it to be round numbers.
The first step is easy because all geometric series with n terms look like this:
x + r * x + r^2 * x + ... + r^(n-1) * x
= x * (1 + r + r^2 + ... + r^(n-1))
= x * (1 + r + r^2 + ... + r^(n-1)) * (r - 1) / (r - 1)
= x * ((r - 1) + (r^2 - r) + (r^3 - r^2) + ... + (r^(n) - r^(n-1)) / (r - 1)
= x * (-1 + (r - r) + (r^2 - r^2) + ... + (r^(n-1) - r^(n-1)) + r^n) / (r - 1)
= x * (r^n - 1) / (r - 1)
So in we want
1000 = x * (r^n - 1) / (r - 1)
= x * (1.75^5 - 1) / (1.75 - 1)
= x * (16.4130859375 - 1) / 0.75
= 20.55078125 x
That gives us the following starting solution.
48.6599505797377
85.154913514541
149.021098650447
260.786922638282
456.377114616993
After that it is a question of tweaking those numbers up and down to get the answer that you want. There are a lot of ways you can do that. One is simply to start with the smallest and move it to a rounded number, and redistribute among the others in proportion to their weights, and continue. That gives you the following sequence of partial answers.
48.6599505797377
85.154913514541
149.021098650447
260.786922638282
456.377114616993
50
85.034965034965
148.811188811189
260.41958041958
455.734265734266
50
75
150.537634408602
263.440860215054
461.021505376344
50
75
150
263.636363636364
461.363636363636
50
75
150
275
450
This is not exactly your desired answer. But it is pretty darned close and hopefully acceptable as a strategy.
UPDATE I had tried 1.75 because it was close to (475/50)^(1/4). When I tried 1.8 instead I got your exact desired answer.
Furthermore note that we do not need to produce all of those intermediate answers. Each time we only need the smallest term. Which is given by target * (r-1) / (r^n - 1). Every time you find the smallest term, you subtract that from the target, reduce n by one, and repeat.
I'm trying to understand reqursion, but I have found one task, I couldn't solve for few days already.
X = 1/1 + 1/(1*2) + 1/(1*2*3) + 1/(1*2*3*4) + 1/(1*2*3*4*5) .....
how can I solve it for 100 repeats without conditional operators?
Can it be solved without recursion?
I've tried this code, but it doesn't work correctly and it contains "If".
public static double harFac(double n) {
if (n == 1) return 1;
return (1.0 / (n * harFac(n - 1))) + harFac(n - 1);
}
I believe you could do something like this:
double result = 0;
int div = 1;
for (int i = 1; i <= 100; i++){
result += 1.0 / div; /*the division needs to take place in floating point*/
div *= i+1;
}
You'll very quickly run into trouble if you evaluate the denominator like that as it will run to a limit very quickly. When working with floating point, it's also a good idea to evaluate the smaller terms first.
Fortunately you can solve both of these problems by recasting the expression to
1 * (1 + 1/2 * ( 1 + 1/3 * (1 + 1/4 * ( ... ) ) ) )
So your final term is in the recursion is foo = 1 + 1.0/100, the penultimate term in the recursion is 1 + 1/98 * foo, and so on.
I personally wouldn't use recursion to solve this, rather use a loop in a single function.
You're along the right lines but you shouldn't be calling harFac twice. You need to instead calculate the divisor. I can't see how you would do this without an if condition, though.
public static double harFac(double n)
{
if (n == 1) return 1;
int divisor = 1;
for (int i = 2; i <= n; ++i) divisor *= i;
return (1.0 / divisor) + harFac(n - 1);
}
This doesn't work beyond around n = 30 because the divisor becomes so massive.