I have this assignment in my Introduction to CompSci class. Our professor says the code is easy to do, we just need to solve the assignment on paper with math. Here is the assignment (NOTE: We mustn't use arrays or any kind of similar stuff, we can only use loops and if):
For the elements of a sequence X0, X1, X2,...,Xn it stands that X0=5, X1=-1,..., Xn+2+2Xn+1+Xn=0. We need to write a program that scans the value of k and prints out Xk.
For max points we need to make X1=A, X2=B where A and B are scanned from keyboard.
Here is my try, I know how to print Xk but I don't know what to print (Since this is Java I will only copy the content of my main):
Scanner in = new Scanner(System.in);
int k=in.nextInt();
int a = 5;
int b = -1;
for(i=3;i<=k;i++)
{
}
I know this is probably demeaning for anybody here to do, but I'm really stuck and I don't know how to solve this one. I have examples of different types of similar assignments that i solved easy but this part Xn+2+2Xn+1+Xn=0 bugs me.
So, the rule is that
Xn+2 + 2 * Xn+1 + Xn = 0
So the value of Xn+2 is
Xn+2 = 0 - 2 * Xn+1 - Xn
Since you know X0 and X1, you can compute X2 using that rule. Since you now know X2 and X1, you can compute X3 using that rule. Since you now know X3 and X2, you can compute X4 using that rule. And you can continue until you know Xk.
The implementation is left as an exercise. The important trick is that all you need to remember (i.e. store in two variables a and b, for example), are the two previous values of Xn+1 and Xn, to be able to compute Xn+2.
As was already stated
Xn+2 = 0 - 2 * Xn+1 - Xn
now, substitute
n = k - 2
and you get
Xk = - 2 * Xk-1 - Xk-2
now, write a function that returns Xk
int x(int k) {
return -2 * x(k - 1) - x(k - 2);
}
Now this is obviously an infinite recursion, so fix it by introducing known values and limits:
int x(int k) {
if (k < 0) throw new runtimeException();
if (k == 0) return 5;
if (k == 1) return -1;
return -2 * x(k - 1) - x(k - 2);
}
This is not an efficient solution, just an exercise.
Related
Given a distance d (going from 0 to d) and 2 points s and e in between which no points can be placed (placing points on s and e is fine, it's not allowed to place points between them).
Place n points such that the distance between each point is as large as possible (distribute them as evenly as possible).
Output the minimal distance between 2 points.
Graphic representation, place n points on the black line (it's a 1-dimensional line) so that the smallest distance between each 2 points is as large as possible (an absolute error of up to 10^(-4) is allowed).
Examples:
d=7, n=2, s=6, e=7, Output is: 7.0000000000
d=5, n=3, s=5, e=5, Output is: 2.5000000006
d=3, n=3, s=0, e=1, Output is: 1.5000000007
d=9, n=10, s=5, e=6, Output is: 1.0000000001
d=6, n=2, s=1, e=6, Output is: 6.0000000000
d=5, n=3, s=4, e=5, Output is: 2.5000000006
My approach:
I tried looking at the intervals separately, distributing points (ideal distribution, lengthOfInterval/n) on the first and second interval (0 to s and e to d) and inspecting all distributions whose number of points sum up to n, I would store a (distribution, largest minimal distance) pair and pick the pair with the largest minimal distance. I don't know how to work with the 10^(-4) tolerance (how does this part even look in code?) and am not sure if my approach is correct. Every suggestion is welcome.
I'm stuck on this question :/
You can use binary search over the possible sizes of gaps between points (from 0 to d) to converge to the largest minimum gap size.
To determine the viability of any given gap size, you basically try to place points from the left and from the right and see whether the gap in the middle is big enough:
Determine how many points can be placed left of s (which is s/gapSize + 1).
Determine how many points will then be required to be placed to the right of e
(which is n - points on left).
Determine how far inwards each side will go.
Check whether the points on the right fits in the gap [e, d] and whether there's at least gap size difference between each side.
Code for this: (note that I worked with number of gaps instead of points, which is just 1 less than the number of points, since it leads to simpler code)
double high = d, low = 0, epsilon = 0.000001;
while (low + epsilon < high)
{
double mid = (low + high)/2;
int gapsOnLeft = (int)(s/mid); // gaps = points - 1
if (gapsOnLeft + 1 > n)
gapsOnLeft = n - 1;
int gapsOnRight = n - gapsOnLeft - 2; // will be -1 when there's no point on the right
double leftOffset = mid*gapsOnLeft;
// can be > d with no point on the right, which makes the below check work correctly
double rightOffset = d - mid*gapsOnRight;
if (leftOffset + mid <= rightOffset && rightOffset >= e)
low = mid;
else
high = mid;
}
System.out.println(low);
Live demo.
The time complexity is O(log d).
The problem with your approach is that it's hard to figure out how big the gaps between points are supposed to be, so you won't know how many points are supposed to go on either side of (s, e) as to end up with an optimal solution and to correctly deal with both cases when s and e are really close together and when they're far apart.
Binary search
Its very easy to find the number of points you can place if the minimum separation distance b/w any pair l is given.
If l=d, then at the most only 2 points can be placed.
..
...
....
so just do a binary search on l.
A crude implementation goes like this.
low,high=0.00001,d
while(high-low>eps):
m = (low+high)/2
if((no. of points placed s.t any pair is at most m units away) >=n):
low=mid
else:
high=mid
TL;DR: Your approach does not always work (and you're not doing it as fast as you could) see the 3rd bullet point for one that works (and uses the given 10^(-4)).
If [s, e] is small and well-placed, then the optimum is just distributing evenly on the whole segment, best value is now d/(n-1). But you'll have to check that none of your elements is between s and e.
Your approach works if s and e are "far enough".
You can do it faster than what you seem to suggest though, by lookign for the best splitting between the two segments in time O(1): if you put n1 (1<=n1<=n-1) elements on the left, you want to maximize min(s/(n1-1), (d-e)/(n-n1-1)) (one of these quantities being possibly +infinity, but then the other is not). The maximum of that function is obtained for s/(x-1) = (d-e)/(n-x-1), just compute the corresponding value for x, and either its floor or ceiling is the best value for n1. The distance obtained is best = min(s/(n1-1), (d-e)/(n-n1-1)) Then you put n1 points on the left, starting at 0, separated by distance best, and n-n1 on the right, starting at d, going left, separated by best.
If the distance between the last point on the left and the first on the right is smaller than best, then you have a problem, this approach does not work.
The complicated case is when the two previous approaches failed: the hole is small and not well placed. Then there are probably many ways to solve the problem. One is to use binary search to find the optimal space between two consecutive points. Given a candidate space sp, try distributing points on the line starting at 0, spaced by sp, as many as you can while remaining below s. Do the same on the right while staying above e and above (last on the left + sp). If you have successfully placed at least n points in total, then sp is too small. Otherwise, it is too big.
Thus, you can use binary search to find the optimal spas follows: start at sp possibly in [max(s, d-e)/(n-1), d/(n-1)]. At each step, take the middle mid of your possible segment [x, y]. Check if the real optimum is above or below mid. According to your case, look for the optimum in [mid, y] or [x, mid]. Stop iff y-x < 10^(-4).
The two previous cases will actually also be found by this method, so you don't need to implement them, except if you want the exact optimal value when possible (i.e. in the first two cases).
It's pretty tricky, except for the simple case (no point lands in the gap):
double dMin = d / (n - 1.0);
if (Math.ceil(e / dMin - 1) * dMin <= s)
return dMin;
Let's continue with the edge cases, placing one point on one side and the rest of the points on the other one:
dMin = Math.min((d - e) / (n - 2.0), e); // one point at 0
double dm = Math.min(s / (n - 2.0), d - s); // one point at d
if (dm > dMin) // 2nd configuration was better
dMin = dm;
And finally for two or more points on both sides:
// left : right = (x - 1) : (n - x - 1)
// left * n - left * x - left = right * x - right
// x * (left + right) = left * n - left + right
// x = (left * n - left + right) / (left + right) = (left * n) / (left + right) - 1
int x = s * n / (d - e + s) - 1;
if (x < 2)
x = 2;
for (int y = x; y <= x + 2 && y < n - 1; y++) {
double dLeft = s / (y - 1.0);
double dRight = (d - e) / (n - y - 1.0);
dm = Math.min(dLeft, dRight);
if (dm > e - s) { // dm bigger than gap
if (dLeft > dRight)
dLeft = e / ((double) y);
else
dRight = (d - s) / ((double) n - y);
dm = Math.min(dLeft, dRight);
}
if (dm > dMin)
dMin = dm;
}
This would be O(1) space and time, but I'm not 100% positive if all cases are checked. Please let me know if it worked. Tested against all the test cases. The above works for n >= 2, if n equals 2 it will be caught by the first check.
Here is an assignment:
"Let's say you are given a number, a, and you want to find its
square root. One way to do that is to start with a very rough guess about
the answer, x0, and then improve the guess using the following formula
x1 = (x0 + a/x0)/2
For example, if we want to find the square root of 9, and we start with x0 = 6,
then x1 = (6 + 9/6)/2 = 15/4 = 3.75, which is closer.
We can repeat the procedure, using x1 to calculate x2, and so on. In this
case, x2 = 3.075 and x3 = 3.00091. So that is converging very quickly on the
right answer(which is 3).
Write a method called squareRoot that takes a double as a parameter and
that returns an approximation of the square root of the parameter, using this
technique. You may not use Math.sqrt.
As your initial guess, you should use a/2. Your method should iterate until
it gets two consecutive estimates that differ by less than 0.0001; in other
words, until the absolute value is less than 0.0001. You can use
Math.abs to calculate the absolute value."
This is exercise meant to practice while loop. As you see I did the assignment, I think it works ? But I am not sure how did I come to solution ? In other words, what should I improve here ? Is there any other way to enter the loop differently ? How to name variables more appropriately ? And lastly, is my approach good or bad here ?
public class squareRoot {
public static void main(String args[]){
System.out.println(squareRoot(192.0));
}
public static double squareRoot(double a){
double gs = a/2; //guess
double ig = (gs + (a/gs))/2; //improving guess
double ig1 = (ig + (a/ig))/2; //one more improving guess, ig1
while (Math.abs((ig-ig1)) > 0.0001){ //with ig and ig1, I am entering the loop
ig = (ig1 + (a/ig1))/2;
ig1 = (ig + (a/ig))/2; //ig1 has to be less then ig
}
return ig1;
}
}
Your approach is nearly correct.
Let's talk about variables first. IMO, you should use full names for variables instead of acronyms. Use guess instead of gs. Use improvedGuess instead of ig etc.
Now that's out of the way we can see where your problem lies. For the while loop to finish, two consecutive guesses' difference must be less than 0.0001. However, here you are only comparing the 1st and 2nd guesses, the 3rd and 4th guesses, the 5th and 6th guesses etc. What if the 4th and 5th guesses' difference is less than 0.0001? Your loop won't stop. Instead, it returns the value of the 6th guess. Although it is more accurate, it does not fulfill the requirement.
Here's what I've come up with
public static double squareRoot(double a){
double guess = a/2;
double improvedGuess = (guess + (a/guess))/2;
while (Math.abs((guess - improvedGuess)) > 0.0001){
guess = improvedGuess;
improvedGuess = (guess + (a/guess))/2;
}
return improvedGuess;
}
Here is my Solution
private static double squareRoot(double a){
double x0= a/2;
while (true) {
double x1 = (x0 + a / x0) / 2;
if (Math.abs(x1 - x0) < 0.0001) {
break;
}
x0=x1;
}
return x0;
}
I have a simple recursive solution as below:
public int countPaths(int x, int y) {
if(x == 0 && y == 0) {
return 0;
} else if(x == 0) {
return 1;
} else if(y == 0) {
return 1;
} else {
int count = countPaths(x-1, y);
count += countPaths(x, y-1);
return count;
}
}
This is to solve the following problem from the book: Cracking the coding interview
Imagine a robot sitting on the upper left corner of an X by Y grid. The robot can only move in two directions: right and down. How many possible paths are there for the robot to go from (0,0) to (X,Y)?
I am trying to ascertain the run time complexity and I believe it is O(x+y). I arrived at this by using a recursion tree, for example if x=2 and y=2
The max depth of this tree is (x+y) and work done at each step is a constant. So max work done is (x+y) * c and hence the run time complexity is O(x+y)
Question 1: Am I correct? I believe the upper bound I have calculated is not tight enough
Question 2: Next, if I were to improve the run time using memoization and hence not repeating computing sub-problems, how would the run time complexity as described by Big-o change?
While it's true that the depth of the tree is O(x+y), there's increasingly many nodes at each layer, and it's the number of nodes that determines complexity, not the depth of the tree.
If you write down recurrence relations for the runtime, you get:
T(0, y) = T(x, 0) = 1
T(x, y) = T(x-1, y) + T(x, y-1) + 1
If you ignore the +1 on the second equation (which can only make the run-time better), you get the same function that your code was computing in the first place, which is choose(x+y, y).
For x=y, this is the central binomial coefficient, which is approximately 4^x/sqrt(pi*x), which for even moderately large values of x is large enough to make the algorithm useless.
With memoisation, you're doing a constant amount of work for each value of x and y, so the complexity is O(xy).
If you evaluate the complexity in terms of the number of additions required to evaluate the count for a given pair (x, y), you get the recurrence
A(x,y) = A(x-1,y) + A(x,y-1) + 1,
with A(x,0) = A(0,y) = 0.
Setting A(x,y) = P(x,y) - 1 the recurrence becomes
P(x,y) - 1 = P(x-1,y) - 1 + P(x,y-1) - 1 + 1,
or
P(x,y) = P(x-1,y) + P(x,y-1),
with P(x,0) = P(0,y) = 1, which gives the classical Pascal's triangle, and
A(x,y) = (x+y)!/(x!y!) - 1.
You can also work with the number of recursive function calls,
C(x,y) = C(x-1,y) + C(x,y-1) + 2,
with C(0,y) = C(x,0) = 0.
You will solve it by setting C(x,y) = 2P(x,y) - 2, and get
C(x,y)= 2(x+y)!/(x!y!)-2.
As regards the asymptotic complexity, this makes no difference. The is no really simpler formula than O((x+y)!/x!y!).
With memoization, every evaluation (with x, y>0) costs only one addition or two calls, and assuming constant time for storage/retrieval of a value the total complexity is the much better O(xy).
Based on the valuable input from #Anonymous, we know the recurrence relation is:
T(x, y) = T(x-1, y) + T(x, y-1) + 1
Abusing (which is ok in Big-O analysis) the notation, let x = y
T(x, x) = 2 * T(x-1, x) = 2 * 2 * T(x-2, x) = ... = 2 * ... * 2 * T(0, x)
= O(2^x)
So the run time complexity is
O(2^n) ; where n = max(x, y)
With memoization, I get it, thank #Anonymous, it should be O(xy)
So, I was putting my knowledge of for loops to the test by attempting to create the mathematical constant π using a series with user-defined accuracy:
public double pi(int accuracy) {
for (int i = 1; i <= accuracy; i++) {
rawPi += 1 / (i * i);
}
return Math.sqrt(rawPi * 6);
}
Now, you would think that this would get closer and closer to π as int accuracy shoots up, but it doesn't. It just stays at the square root of 6, meaning that private double rawPi gets to 1 and never goes any higher, meaning no terms are being added in my series (represented as a for loop) and I have absolutely no idea what the problem could be. Any ideas?
Try to change this:
rawPi += 1 / (i * i);
to
rawPi += 1.0 / (i * i);
or as commented by "Patricia Shanahan" , use this for better accuracy and to avoid integer overflow on i*i:
1/((double)i*i)
How does one figure out how many times one has to add a short to get the value of another short?
I know, I know, it's a weirdly phrased question. But in more specifics without all the primitive types of Java...
Basically, I have a short x, which we'll use the placeholder 7 for. I also have a short y, which I'll say is the number 5. And then, I have a short z, which I'll say is 236.
Now, what I want to do, is get an integer that counts how many times I have to add the number y (5) to the number x (7) to get to the maximum value of z (236).
Obviously, I could do that somewhat with a pencil and paper right now, but what I need is something that I can input the 3 values and it will give me the integer as the output - the number of times I have to add the value y to the number x to get to the maximum value of z.
If you still don't understand what I'm doing, then a more visual example is:
(Y * someint) + X = Z How would I get to someint?
int result = (z - x) / y;
The result is int even if division has a remainder which is ignored in this case.
As others have stated this is simple division. But if you're looking for other completely unnecessary ways to do this, heres a loop way...
public static int getNumOfAdds(short x, short y, short target){
int i;
for(i = 0; y*i + x < target; i++){}
return i;
}
val = (Z-X)/Y;
rem_val = (Z-X)%Y;
if (rem_val != 0)
val++;
This should do it.
Recursively?
Try something like
Func(short x , short y, short z, int c)
if ( x >= z )
return c
else
return Func(x+y,y,z,c)
and your first call would be Func(x,y,z,0)