I'm trying to work out the "towers of hanoi" problem, which moves stacks of disks organized from smallest to largest from a start stack to a destination stack, by means of an auxiliary stack without ever placing a larger disk on top of a smaller disk.
I was given the algorithim:
If numberDisks == 1:
Display “Move the top disk from S to D”.
Else
Move(numberDisks -1, ‘S’, ‘A’, ‘D’);
Move(1, ‘S’, ‘D’, ‘A’);
Move(numberDisks -1, ‘A’, ‘D’, ‘S’);
However this seems to differ from most other examples which seem to work without using Move(1, ‘S’, ‘D’, ‘A’); in the recursive function.
As my code stands, I seem repeat the base case for every move, and im not sure how to structure my print statements to give the proper output which should look like:
Move disk 1 from S to D
Move disk 2 from S to A
Move disk 1 from D to A
Move disk 3 from S to D
Move disk 1 from A to S
Move disk 2 from A to D
Move disk 1 from S to D
When trying to move 3 disks.
// Recursively solve Towers of Hanoi puzzle
public static void main(String[] args) {
if (handleArguments(args)) {
System.out.println("numDisks is ok");
int numDisks = Integer.parseInt(args[0]);
Move(numDisks,'s', 'a', 'd' );
}
}
// recursive case
public static void Move(int disks, char start, char aux, char destination) {
// base case
if (disks == 1) {
System.out.println("Move disk 1 from S to D");
// if number of disks is 2 or greater
} else if(disks > 1) {
Move(disks - 1, start, aux, destination);
System.out.println("move disk " + disks + " from " + start + " to " + destination);
Move(1, start, destination, aux);
Move(disks - 1, aux, destination, start);
}
}
First thing: Understand the algorithm for moving n discs (from S to D, with A)
If there is only one disc to move, just move it then stop*.
Move n - 1 discs from S to A, with D.
Move nth disc from S to D
Move n - 1 discs from A to D, with S.
*Equally: If there are 0 discs, just stop. (Some would argue that this is the superior termination condition because, in your code, it will prevent the print statement when there is one from being a special case, it will be handled naturally by the print statement you cover step 3 with. When, for example, you decide to change this method to return a list of the steps instead of printing it, this change will only have to be applied in one place)
You mention that "I seem repeat the base case for every move." If you look at your code, and compare to my statements above. You will see that you call Move(1, start, destination, aux); between my steps 3 and 4. This is why you are repeating your base case, because you are explicitly calling, repeating your base case, but it doesn't make any sense to.
The other main problem I can see:
System.out.println("Move disk 1 from S to D"); will always print 'S' and 'D', in that order, when often you will need to specify a different move, ensure to use the arguments for this statement.
I don't think that there is anything else, but try it and see.
In response to the example you were given, in the start of your post. It produces subtly different output than your version.
Yours specifies (or attempts to) which size disc should be moved at each step, the example only specifies which stack to move a disc from and to, regardless of its size.
The recursive call with 1 as its argument in the middle there is to print the move instruction for moving the final disc in the stack (my step 3).
Related
I have written a bigger program, I am constructing a graph Graph(V,E), from words in a data file. Then I am parsing another file with words on same line: "other there" <-- like that, the first string is start word, the second is end word, as seen below:
while (true) {
String line = reader.readLine();
if (line == null) { break; }
assert line.length() == 11;
String start = line.substring(0, 5);
String goal = line.substring(6, 11);
System.out.println(
G.findShortestPath(
words.indexOf(start),
words.indexOf(goal)));
}
I am using undirected graphs with BFS. I am doing word transformation word chain, like this: climb → blimp → limps → pismo → moist → stoic
The input file contains words of length five, and a path/connection is defined as such so it goes from Xto Y in one step, only if, and only if the four last letters in Xare found in Y.
What is known, and I have calculated.
Time complexity: O(V + E) for building the graph G(V, E) of words. The second part of the program consists of a while loop and a for loop of finding the shortest path (using BFS), which is O(V^2).
Space complexity: O(V) in the worst case. The graph holds all the words. The nodes are made up of a single node class object which contains n neighbor(s).
Process:
Program loads into buffer a file with words.
The program builds the graph.
The program runs test and loads into buffer information from a test file (different file). Then selects start and end node and performs the shortest path search.
If there's a connection, the code returns the shortest path length. If there's no connection between two words or end/goal cannot be reached, we return -1.
Now, I am trying to come up with an O(?) time algorithm or total time complexity for V,E,F, where:
V is the number of vertices
E is the number of edges
F is the number of test cases (number of lines in the test file)*
*Number of test cases in function: public void performTest(String filename) throws IOException. The body of such function is here, see above. Now, I know, that for lines n, there will be same n amount of test cases. F=O(n). But, in what way, can one incorporate or add this calculation to make a general O expression with variables that holds for whatever amount of words in list and words in graph and words from testfile.
The main body of the BFS algorithm is the nesting of two loops, the while loop visits each vertex once, so it is O(|V|), and the for nested in the while , Since each edge will be checked only once when its starting vertex u is dequeued, and each vertex will be dequeued at most once, so the edge will be checked at most once, and the total is 0 (|E|).The time complexity of BFS is 0 (|V|+|E|)
Contents in Testfile:
The first word becomes the starting word, the second on the same line becomes the end or target word.
blimp moist
limps limps
Some other code, I've written previously:
public static void main(String... args) throws IOException {
ArrayList<String> words = new ArrayList<String>();
words.add("their");
words.add("moist");
words.add("other");
words.add("blimp");
Graph g = new Graph(words.size());
for(String word: words) {
for(String word2: words){
g.addEdge(words.indexOf(word), words.indexOf(word2));
}
}
BufferedReader readValues = null;
try {
readValues =
new BufferedReader(new InputStreamReader(new FileInputStream("testfile.txt")));
String line = null;
while ((line = readValues.readLine()) != null) {
// assert line.length() == 11;
String[] tokens = line.split(" ");
String start = tokens[0];
String goal = tokens[1];
BreadthFirstPaths bfs = new BreadthFirstPaths(g, words.indexOf(start));
if (bfs.hasPathTo(words.indexOf(goal))) {
System.out.println("Shortest path distance from " + start + " to " + goal + " = " + bfs.distTo(words.indexOf(goal)));
} else System.out.println("Nothing");
}
} finally {
if (readValues != null) {
try {
readValues.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Notice: Not interested in FASTER solutions.
The straightforward answer:
The direct approach would be to use Floyd - Warshall algorithm. This algorithm computes shortest paths between all pairs of vertices in a directed graph without negative cycles. Since you are using an undirected graph with positive weights it is sufficient to replace every undirected edge (u,v) with directed pair (u,v), (v,u).
The runtime of Floyd - Warshall is O(V ^ 3) and it would compute all the answers you could ever seek at once, given that you can retrieve them in a reasonable time. (Which should be rather easy since you already have V^3 of a breathing room).
Getting faster:
In your case that most likely isn't optimal(Not to mention that I don't know how many queries will you make - if only a few, then FW is definitely an overkill). Since your graph doesn't have any negative edges and it seems that the edge count is only C * |V| from your space complexity we can go further. Enters Djikstra.
Djikstra algoritm's complexity is O(E + Vlog(V)).
Considering that you most likely have only ~ C * V edges, this would bring the repeated Djikstra's computation costs to F * O(V * log(V)).
And faster:
If you wish to give frying your brain a go, Djikstra can be improved upon in some special cases by using the dark magic of the fibonacci heaps(which are modified for the purpose of the algorithm to make things more confusing). From what I can see, your case could be special enough so that the O(N * sqrt(log(N))) from this article is achievable.Their assumption are:
n vertices
m edges
the the longest arc(a length of an edge if my google-fu is correct) being bounded by a polynomial function of n.
This is it for my attempt at a quick dive into the shortest path problem. If you wish to research more, I would recommend looking into the all-pairs-shotest-paths problem in general. There are many other algorithms that are similar in the complexity. Your ideal approach will also depend on your F.
P.S.:
Unless you have many, many words, your neighbor count can still be rather big: 5! * 26 in the worst case to be precise. (Four letters are fixed and one is arbitrary - possible permutations * letter count). Can be lower in case of repetitions, still it isn't small, although it can technically be considered a constant.
It seems to me that you are simply asking about the computational complexity of your existing solution, expressed in terms of the 3 variables V, E and F.
If I am reading your question correctly, it is
O(V + E) // loading
+ O(V^2) done F times // F test cases
which simplifies to:
O(V + E + (F * V^2))
This assumes that your Big-O characterizations of the load and search times are correct. We cannot confirm1 that those characterizations are correct without seeing the complete Java source code for your solution. (An English or pseudo-code description is too imprecise.)
Note that the above formula is "canonical". It cannot be simplified further unless you eliminate variables; e.g. by treating them as a constant or placing bounds on them.
However, if we can assume that F > 0, we can reduce it to:
O(E + (F * V^2))
since when F > 0 the F*V^2 term will dominate the V term as either F or V tends to infinity. (Intuitively, the F == 0 case corresponds to just loading the graph and running no test cases. You would expect the performance characteristics to be different in that case.)
It is possible that the E variable could be approximated as function of V. (Each edge from one node to another represents a permutation of a word with one letter changed. If one did some statistical analysis of words in the English language, it may be possible to determine a the average number of edges per node as a function of the number of nodes.) If we can prove that this (hypothetical) average_E(V) function is O(V^2) or better (as seems likely!), then we can eliminate the E term from the overall complexity class.
(Of course, that assumes that the input graph contains no duplicate or incorrect edges per the description of the problem you are trying to solve.)
Finally, it seems that the O(V^2) is actually a measure of worst-case performance, depending on the sparseness of the graph. So you need to factor that into your answer ... and the way that you attempt to validate the complexity.
1 - The O(V^2) seems a bit suspicious to me.
Time: O(F * (V + E))
Space: O(V + E)
Following what you described
V: Vertices
E: Edges
F: path queries
The BFS algorithm complexity is O(V + E) time, and O(V) space
Each query is a BFS without any modification, so the time complexity is O(F * (V + E)), and space complexity is the same as one single BFS since you are using the same structure O(V), but we have to consider the space used to store the graph O(E).
Graph construction, you are iterating over all pairs of words and adding one edge for each word your graph always have $E = V^2$. If you had asked advice to improve your algorithm as is usual in this community, I would tell you to avoid adding edges that should not be used (those with more than 1 character difference).
I have to make a iterative solution to the Towers of Hanoi problem. I am trying to convert a tail recursive call to an iterative one. I am following an algorithm I found in my textbook to transform it. I followed this algorithm and even though my code is similar to the recursive variant my output doesn't match the designated form. Now from what the book tells me, having a recursive call with an iterative is strange, but valid.
public class DemoIterative
{
public static void TowersOfHanoi(int numberOfDisks,
String startPole, String tempPole, String endPole)
{
while (numberOfDisks > 0)
{
/** MUST GO 1, 3, 2, 1 */
TowersOfHanoi(numberOfDisks - 1, startPole, endPole, tempPole);
System.out.println(startPole + " -> " + endPole);
numberOfDisks = numberOfDisks - 1;
startPole = tempPole;
tempPole = startPole;
}
}
public static void main(String[] args)
{
DemoIterative demoIterative = new DemoIterative();
System.out.println("Enter amount of discs: ");
Scanner scanner = new Scanner(System.in);
int discs = scanner.nextInt();
demoIterative.TowersOfHanoi(discs, "A", "B", "C");
} // end of main
} // end DemoIterative
Now the output I am getting from this is:
A to C,
A to B,
C to B,
A to C,
B to B,
B to C,
B to C
I should be getting this (tested from recursive original):
A to C,
A to B,
C to B,
A to C,
B to A,
B to C,
A to C
This is the algorithm I am using:
While numberOfDisks is greater than 0, move disk from startPole to endPole, numberOfDisks--, exchange the contents of tempPole and startPole.
Now is this possible? If so, is there a problem with my algorithm or am I printing it wrong?
You have a problem with your algorithm. Most important for your own understanding of this, slap a print statement at the top of your routine and print out the arguments. Also insert one at the bottom of the loop to help track that execution.
To summarize, I don't think you understand the call tree you've created, and I think you should trace it to see. There are applications that will use such a tree, but I don't think that this what you want for this assignment.
There area couple of structural problems. For one, when you get to the bottom of the loop, you set startPole = tempPole, and follow that with a useless assignment back -- this wipes out the old startPole value; it does not exchange them.
Next, your loop + recursion structure is strange. First, you've used a while loop where the semantics clearly indicate a for -- you know how many times you'll iterate when you enter the loop. When you first call this with, say, 5 disks, the numberOfDisks (I'll call it N) = 5 iteration will loop 5 times. Each iteration recurs with N = 4, 3, 2, 1, respectively.
Now, the N=4 instance will do likewise: recurring with N=3, 2, 1. This gives you two instances at N=3. Continuing, you'll get three instances at N=2, and four at N=1, for a total of 11 calls to your function. Since only four of these involve moving a one-disk stack (for a tower of 5 disks, you need several more), I think you've incorrectly implemented whatever you had in mind.
I am trying to implement a 2 dimensional matrix as a maze. There is a starting point, an ending point (randomly chosen). And to make it little complicated, there are obstacles and agents. If the rat runs into an obstacle, it should backtrack and find the correct path. If it runs into an agent, it gets destroyed.
Here's a sample 4x4 matrix
1 7 1 1
2 1 1 0
1 0 1 0
1 1 1 9
Key: 0 is an obstacle, 2 is an agent, 7 is the starting point, 9 is the goal/ending point. 1 means that is is safe to move there.
The correct solution for this matrix would be:
0 1 1 0
0 0 1 0
0 0 1 0
0 0 1 1
But the rat is not intelligent (at least for this program) , so I am implementing a brute force algorithm, with random moves.
I have tried to implement this using a recursive function called mazeUtil().
Below is the function:
maze[][] is the randomized initial matrix that the rat moves through.
solution[][] is the solution matrix that will keep track of the moves.
(x, y) is the current position in the grid
n is the size of the matrix (it is a square matrix).
public static void mazeUtil(int maze[][], int solution[][], int x, int y, int n)
{
if(x == goal[0] && y == goal[1])
{
solution[x][y] = 1;
return;
}
int check = moveCheck(maze, x, y, n);
//moveCheck() return 0 for Obstacle, 1 for safe path, 2 for agent, 7 for starting point (also safe path), 9 for goal (safe path)
if (check == 2){
solution[x][y] = 1;
out.println("Oops! Ran into an agent!");
return;
}
else if(check == 0)
{
//What should I put here?
}
else if(check == 1 || check == 7 || check == 9)
{
solution[x][y] = 1;
Random newRandom = new Random();
int temp = newRandom.nextInt(3);
if(temp == 0){ //move up if possible? x--
if(x > 0)
mazeUtil(maze, solution, x-1, y, n);
else
mazeUtil(maze, solution, x+1, y, n);
}
else if (temp == 1){
if (x < n-1)
mazeUtil(maze, solution, x+1, y, n);
else
mazeUtil(maze, solution, x-1, y, n);
}
else if(temp == 2){
if (y < n-1)
mazeUtil(maze, solution, x, y+1, n);
else
mazeUtil(maze, solution, x,y-1, n);
}
else if (temp == 3){
if (y > 0)
mazeUtil(maze, solution, x, y-1, n);
else
mazeUtil(maze, solution, x, y+1, n);
}
}
}
I have to randomize the moves and that's why i have used random function. My function works quite well if it runs into an agent (2). I have also prevented the rat from going out of boundary. And it doesn't have any problem going through the safe path (1). But the problem is when it hits an obstacle. I'm thinking about backtracking. How do I add that into my function? Like save the last step, and do the reverse? And it is quite possible that there is no solution in the maze like this one
7 0 0 9
2 0 1 1
0 1 0 0
1 2 0 1
It would hit an obstacle if it goes right, and hit an agent if it goes down. It cannot move diagonally.
That brings me to my second question, how would I terminate my recursive function in that case.
At this point the only time it terminates is when it reaches the goal or hits an agent.
Any help would be appreciated. Thanks in advance
Well, let's imagine I need to solve the same problem by the same way you are solving it.
(I think the best solution for it is Path finding, as already mentioned in comments).
I will create
class Point{
public int x;
public int y;
}
and store coordinates in it.
I will store all points the rat visited in List<Point> path
In this solution you do not have problems with previous point (it is the last point in list)
As for algorithm termination -- you use algorithm with randoms. So you can't be sure that your rat will solve the simplest maze like
7 1 1
1 1 1
1 1 1
it is possible that rat will move from (0,0) to (1,0) and from (1,0) to (0,0) forever.
So, let's again imagine that I need to improve your algorithm instead of using good one.
I will store number of times the rat returned back from obstacle or visited the point in path list.
If this number > 4 I will command to my rat return back to the original point (point 7). And start the journey again.
If the rat need to return back, for example 10 times, the algorithm terminates.
Again, your algorithm is funny, and it should be interesting to see how the rat moves but it does not solve the problem. It will not work on big mazes.
Try to implement path finding. If you will have problems -- ask questions.
Good luck!
A quick point on style, to save some typing later: maze[][], solution[][] and n are all effectively global, and do not change between recursive calls (maze and solution are just passed as references to the same arrays, and n never changes). This is purely style, but you can write this as:
private static int[][] maze;
private static int[][] solution;
private static int n;
public static void mazeUtil(int x, int y) {
...
}
So on to your solution: the first point is I don't see how you know when you've reached the goal; your mazeUtil function does not return anything. For this kind of recursion, a general approach is for your solver function to return a boolean: true if the goal has been reached and false if not. Once you get a true, you just pass it back all the way up the call stack. Each time you get a false, you backtrack to the next solution.
So I'd suggest:
public static boolean mazeUtil(int x, int y) {
// return true if goal found, false otherwise
...
}
Next, I'm not sure what the practical difference between an agent and an obstacle is: running in to either causes you to backtrack. So I'd think that bit of code would be:
if (check == 2) {
out.println("Oops! Ran into an agent!");
return false;
}
if (check == 0)
out.println("Oops! Ran into an obstacle!");
return false;
}
Then the recursive bit: one point here is you do not ever reset the solution to 0 for failed attempts (actually, as the final algorithm will never backtrack more than a single step this is not actually that important, but it's good to illustrate the general approach). Given what we have so far, this should now be something like:
if (check == 9) {
out.println("Found the goal!");
return true;
}
if (check == 1 || check == 7) {
// add current position to solution
solution[x][y] = 1;
// generate random move within bounds
int nextX = ...
int nextY = ...
if (mazeUtil(nextX, nextY)) {
// we've found the solution, so just return up the call stack
return true;
}
// this attempt failed, so reset the solution array before returning
solution[x][y] = 0;
return false;
}
// shouldn't ever get here...
throw new IllegalStateException("moveCheck returned unexpected value: " + check);
Right, so far so good, but there's still a problem. As soon as one of the mazeUtil calls returns a value (either true or false) it will return that all the way up the calls stack. So if you happen to find the exit before an agent or an obstacle, all good, but that's quite unlikely. So instead of trying a single move when recursing, you need to try all possible moves.
WIth a supporting class Point, containing a simple x and y pair:
if (check == 1 || check == 7) {
// add current position to solution
solution[x][y] = 1;
// generate an array of all up/down/left/right points that are within bounds
// - for a random path need to randomise the order of the points
Point[] points = ...
for (Point next : points) {
if (mazeUtil(next.x, next.y)) {
// we've found the solution, so just return up the call stack
return true;
}
}
// this attempt failed, so reset the solution array before returning
solution[x][y] = 0;
return false;
}
And I think that's about as far as you can go with a totally ignorant rat! To see how this works, consider the following maze:
7 1
0 9
Starting at "7", possible moves are Down and Right.
If you try Down first, it returns false, so the only option left is
Right, so you end up on the "1".
If you try Right first, you still end up on the "1".
From the "1", possible moves are Down and Left:
If you try Down first, it returns true, which bubbles up the call stack - success!
If you try Left first, you end up on the "7", so recurse to the previous step.
And that's all that can ever happen. So using * for a return-false-backtrack, and ! for a success, any of the following are possible:
R-D!
R-L-D*-R-D!
R-L-R-L-R-L-R-L (keep going for a long, long time....) R-L-R-D!
So for a solvable maze, and a truly random generator, this will eventually solve the maze, although it could take a very long time. Something to note with this though, is it does not really backtrack that much: only ever a single step from a 2 or 0 node.
However, there's still the problem of the unsolveable maze, and I don't think that is possible given a totally ignorant rat. The reason for this is that for a brute force recursion like this, there are only two possible termination conditions:
The goal has been found.
All possible paths have been tried.
And with a totally ignorant rat, there is no way to detect the second!
Consider the following maze:
7 1 1 1
0 0 0 0
0 0 0 0
1 1 1 9
The totally ignorant rat will just wander left and right across the top row forever, and so the program will never terminate!
The solution to this is that the rat must be at least a bit intelligent, and remember where it has been (which will also make the solveable maze run quicker in most cases and backtrack along entire paths instead of only for single nodes). However, this answer is getting a bit too long already, so if you're interested in that I'll refer you to my other maze-solving answer here: Java Recursive Maze Solver problems
Oh, just two final points on Random:
You don't need to create a new Random each time - just create a
global one and call nextInt each time.
nextInt(n) returns between 0 (inclusive) and n (exclusive), so you
need nextInt(4) not nextInt(3).
Hope this all helps!
if you want to move in random, u need to know the states you've been already in them, so u will need a tree, otherwise u can keep the most left path when the rat is in multi way place.
now lets think of recursive + random. it can not be that hard. you can have a function that returns the list of points it has been in them, and get correct position as input, there is a bit of problem and the idiot rat can got back the way he already came from, so lets solve it with adding previous point as another input for our function.
every thing in place. now we wana know if the idiot rat runs into a dead path or an agent. how about making 2 exceptions for this situations and handling them in recursive function??
well, i don't think there will be any more problems on way. actually i'm temped to try it myselft. that would be fun :D
good luck with the idiot rat
I'd like to do some analysis of your algorithm design before proposing a solution.
You mention that you want to use a random walk algorithm. No problem with that it's a perfectly acceptable (though not necessarily efficient) way to look for a path. However you need to be aware that it has some implications.
In general random walk will not tell you when there is no solution. If you just keep trying paths at random you will never exhaust the search tree.
If this is unacceptable (i.e. it needs to be able to halt when there is no soltuion) then you need to keep a record of paths already attempted and randomise only those not yet attempted.
Random walk won't necessarily find the optimal solution unless there is only one solution. In other words if there are loops / multiple paths in your maze then there's no guarantee you are finding the fastest.
I can't actually see the difference between agents and obstacles in your problem. In both cases you need to backtrack and find another path. If there is a difference then you'll need to point it out.
So assuming your maze could have zero or more successful paths and you are not looking for the optimal path (in which case you really should use A* or similar), the structure of a solution should look something like:
public List<Position> findPath(Set<Position> closedSet, Position from, Position to) {
if (from.equals(to))
return List.of(to);
while (from.hasNeighboursNotIn(closedSet)) {
Position pos = from.getRandomNeighbourNotIn(closedSet);
closedSet.add(pos);
List<Position> path = findPath(closedSet, pos, to);
if (!path.isEmpty())
return List.of(pos, path);
}
closedSet.add(from);
return Collection.EMPTY_LIST;
}
This uses lots of pseudo-code (e.g. there is no List.of(item, list)) but you get the idea.
I'm studying for CS interviews and I decided to try making up my own problem and solving it recursively.
The question I am trying to solve is this: I want to be able to write a recursive function that finds the nth row of pascal's triangle.
Ex pascals(1) -> 1
pascals(2) -> 1,1
pascals(3) -> 1,2,1
I believe I have solved this function. It takes a helper function to get it started with the base case.
function int[] nthPascal(int[] a, int n){
// in the case that the row has been reached return the completed array
if(n==1){
return a;
}
// each new row of pascal's triangle is 1 element larger. Ex 1, 11, 121,1331 etc.
int[] newA = new int[a.length()+1];
//set the ends. Technically this will always be 1.
// I thought it looked cleaner to do it this way.
newA[0]=a[0];
newA[newA.length-1]=a[a.length-1];
//so I loop through the new array and add the elements to find the value.
//ex 1,1 -> -,2,- The ends of the array are already filled above
for(int i=1; i<a.length; i++){
// ex 1+1 = 2 for 1,1 -> 1,2,1
newA[i]=a[i-1]+a[i]
}
//call the recursive function if we are not at the desired level
return nthPascal(newA,n-1);
}
/**
*The helper function
*/
public int[] helperPascal(int n){
return nthPascal(int[] {1},n);
}
My question is how do I find the bigO cost?
I am familiar with common algorithm costs and how to find them. The recursion in this makes it confusing for me.
I know it's clearly not constant, n, nlogn, etc. My thought was that it was 3^n?
I searched for an example and found:
Pascal's Triangle Row Sequence
and
What is the runtime of this algorithm? (Recursive Pascal's triangle).
But they are trying to find a specific element in a given location I believe. I couldn't find anyone implementing pascal's triangle this way and talking about bigO cost.
Is this because there is a better way to write a recursive row finding pascal's function? If so please share :)
Each time you call nthPascal, it calls itself recursively just once. Therefore, you can get the time complexity by adding the time complexities of each invocation of the function (excluding the recursive call). (If you had a function that traverses a binary tree, it would typically call itself recursively twice, which makes the computation more complicated. Here, though, since it calls itself only once, the computation is pretty simple.)
Each invocation of the function has a loop that executes a.length times, and the body of the loop executes in constant time. There aren't any other loops or any other statements that execute in anything but constant time, except for when you allocate the array intA because Java will intialize every element of the array. The result, though, is that when you call nthPascal with an array of length M, the execution time will be O(M) not counting the recursive call.
So assuming that the execution time is roughly M*k for some constant k, that means the total execution time will be 1*k + 2*k + 3*k + ... + (n-1)*k. And 1 + 2 + 3 + ... + n - 1 is (n * (n - 1)) / 2, which is O(n2). So O(n2) is the answer you're looking for.
For each recursive call, you are doing a for loop of size k, where k is the depth of the recursive call (at depth k, you have an array of size k).
To get the complete row at depth n, you call nthPascal at depth 1, 2, ..., n.
Therefore, your total complexity will be 1+2+...+n=n(n+1)/2 = O(n²).
Code 1:
public static int fibonacci (int n){
if (n == 0 || n == 1) {
return 1;
} else {
return fibonacci (n-1) + fibonacci (n-2);
}
}
How can you use fibonacci if you haven't gotten done explaining what it is yet? I've been able to understand using recursion in other cases like this:
Code 2:
class two
{
public static void two (int n)
{
if (n>0)
{
System.out.println (n) ;
two (n-1) ;
}
else
{
return ;
}
}
public static void main (String[] arg)
{
two (12) ;
}
}
In the case of code 2, though, n will eventually reach a point at which it doesn't satisfy n>0 and the method will stop calling itself recursively. In the case of code 2, though, I don't see how it would be able to get itself from 1 if n=1 was the starting point to 2 and 3 and 5 and so on. Also, I don't see how the line return fibonacci (n-1) + fibonacci (n-2) would work since fibonacci (n-2) has to contain in some sense fibonacci (n-1) in order to work, but it isn't there yet.
The book I'm looking at says it will work. How does it work?
Well, putting aside what a compiler actually does to your code (it's horrible, yet beautiful) and what how a CPU actually interprets your code (likewise), there's a fairly simple solution.
Consider these text instructions:
To sort numbered blocks:
pick a random block.
if it is the only block, stop.
move the blocks
with lower numbers to the left side,
higher numbers to the right.
sort the lower-numbered blocks.
sort the higher-numbered blocks.
When you get to instructions 4 and 5, you are being asked to start the whole process over again. However, this isn't a problem, because you still know how to start the process, and when it all works out in the end, you've got a bunch of sorted blocks. You could cover the instructions with slips of paper and they wouldn't be any harder to follow.
In the case of code 2 though n will eventualy reach a point at which it doesnt satisfy n>0 and the method will stop calling itself recursivly
to make it look similar you can replace condition if (n == 0 || n == 1) with if (n < 2)
Also i don't see how the line `return fibonacci (n-1) + fibonacci (n-2) would work since fibbonacci n-2 has to contain in some sense fibonacci n-1 in order to wrok but it isn't there yet.
I suspect you wanted to write: "since fibbonacci n-1 has to contain in some sense fibonacci n-2"
If I'm right, then you will see from the example below, that actually fibonacci (n-2) will be called twice for every recursion level (fibonacci(1) in the example):
1. when executing fibonacci (n-2) on the current step
2. when executing fibonacci ((n-1)-1) on the next step
(Also take a closer look at the Spike's comment)
Suppose you call fibonacci(3), then call stack for fibonacci will be like this:
(Veer provided more detailed explanation)
n=3. fibonacci(3)
n=3. fibonacci(2) // call to fibonacci(n-1)
n=2. fibonacci(1) // call to fibonacci(n-1)
n=1. returns 1
n=2. fibonacci(0) // call to fibonacci(n-2)
n=0. returns 1
n=2. add up, returns 2
n=3. fibonacci(1) //call to fibonacci(n-2)
n=1. returns 1
n=3. add up, returns 2 + 1
Note, that adding up in fibonacci(n) takes place only after all functions for smaller args return (i.e. fibonacci(n-1), fibonacci(n-2)... fibonacci(2), fibonacci(1), fibonacci(0))
To see what is going on with call stack for bigger numbers you could run this code.
public static String doIndent( int tabCount ){
String one_tab = new String(" ");
String result = new String("");
for( int i=0; i < tabCount; ++i )
result += one_tab;
return result;
}
public static int fibonacci( int n, int recursion_level )
{
String prefix = doIndent(recursion_level) + "n=" + n + ". ";
if (n == 0 || n == 1){
System.out.println( prefix + "bottommost level, returning 1" );
return 1;
}
else{
System.out.println( prefix + "left fibonacci(" + (n-1) + ")" );
int n_1 = fibonacci( n-1, recursion_level + 1 );
System.out.println( prefix + "right fibonacci(" + (n-2) + ")" );
int n_2 = fibonacci( n-2, recursion_level + 1 );
System.out.println( prefix + "returning " + (n_1 + n_2) );
return n_1 + n_2;
}
}
public static void main( String[] args )
{
fibonacci(5, 0);
}
The trick is that the first call to fibonacci() doesn't return until its calls to fibonacci() have returned.
You end up with call after call to fibonacci() on the stack, none of which return, until you get to the base case of n == 0 || n == 1. At this point the (potentially huge) stack of fibonacci() calls starts to unwind back towards the first call.
Once you get your mind around it, it's kind of beautiful, until your stack overflows.
"How can you use Fibonacci if you haven't gotten done explaining what it is yet?"
This is an interesting way to question recursion. Here's part of an answer: While you're defining Fibonacci, it hasn't been defined yet, but it has been declared. The compiler knows that there is a thing called Fibonacci, and that it will be a function of type int -> int and that it will be defined whenever the program runs.
In fact, this is how all identifiers in C programs work, not just recursive ones. The compiler determines what things have been declared, and then goes through the program pointing uses of those things to where the things actually are (gross oversimplification).
Let me walkthrough the execution considering n=3. Hope it helps.
When n=3 => if condition fails and else executes
return fibonacci (2) + fibonacci (1);
Split the statement:
Find the value of fibonacci(2)
Find the value of fibonacci(1)
// Note that it is not fib(n-2) and it is not going to require fib(n-1) for its execution. It is independent. This applies to step 1 also.
Add both values
return the summed up value
The way it gets executed(Expanding the above four steps):
Find the value of fibonacci(2)
if fails, else executes
fibonacci(1)
if executes
value '1' is returned to step 1.2. and the control goes to step 1.3.
fibonacci(0)
if executes
value '1' is returned to step 1.3. and the control goes to step 1.4.
Add both
sum=1+1=2 //from steps 1.2.2. and 1.3.2.
return sum // value '2' is returned to step 1. and the control goes to step 2
Find the value of fibonacci(1)
if executes
value '1' is returned
Add both values
sum=2+1 //from steps 1.5. and 2.2.
return the summed up value //sum=3
Try to draw an illustration yourself, you will eventually see how it works. Just be clear that when a function call is made, it will fetch its return value first. Simple.
Try debugging and use watches to know the state of the variable
Understanding recursion requires also knowing how the call stack works i.e. how functions call each other.
If the function didn't have the condition to stop if n==0 or n==1, then the function would call itself recursively forever.
It works because eventually, the function is going to petter out and return 1. at that point, the return fibonacci (n-1) + fibonacci (n-2) will also return with a value, and the call stack gets cleaned up really quickly.
I'll explain what your PC is doing when executing that piece of code with an example:
Imagine you're standing in a very big room. In the room next to this room you have massive amounts of paper, pens and tables. Now we're going to calculate fibonacci(3):
We take a table and put it somewhere in the room. On the table we place a paper and we write "n=3" on it. We then ask ourselves "hmm, is 3 equal to 0 or 1?". The answer is no, so we will do "return fibonacci (n-1) + fibonacci (n-2);".
There's a problem however, we have no idea what "fibonacci (n-1)" and "fibonacci (n-2)" actually do. Hence, we take two more tables and place them to the left and right of our original table with a paper on both of them, saying "n=2" and "n=1".
We start with the left table, and wonder "is 2 equal to 0 or 1?". Of course, the answer is no, so we will once again place two tables next to this table, with "n=1" and "n=0" on them.
Still following? This is what the room looks like:
n=1
n=2 n=3 n=1
n=0
We start with the table with "n=1", and hey, 1 is equal to 1, so we can actually return something useful! We write "1" on another paper and go back to the table with "n=2" on it. We place the paper on the table and go to the other table, because we still don't know what we're going to do with that other table.
"n=0" of course returns 1 as well, so we write that on a paper, go back to the n=2 table and put the paper there. At this point, there are two papers on this table with the return values of the tables with "n=1" and "n=0" on them, so we can compute that the result of this method call is actually 2, so we write it on a paper and put it on the table with "n=3" on it.
We then go to the table with "n=1" on it all the way to the right, and we can immediately write 1 on a paper and put it back on the table with "n=3" on it. After that, we finally have enough information to say that fibonacci(3) returns 3.
It's important to know that the code you are writing is nothing more than a recipe. All the compiler does is transform that recipe in another recipe your PC can understand. If the code is completely bogus, like this:
public static int NotUseful()
{
return NotUseful();
}
will simply loop endlessly, or as in my example, you'll keep on placing more and more tables without actually getting anywhere useful. Your compiler doesn't care what fibonacci(n-1) or fibonacci(n-2) actually do.