I have an algorithm, and I want to figure it what it does. I'm sure some of you can just look at this and tell me what it does, but I've been looking at it for half an hour and I'm still not sure. It just gets messy when I try to play with it. What are your techniques for breaking down an algoritm like this? How do I analyze stuff like this and know whats going on?
My guess is its sorting the numbers from smallest to biggest, but I'm not too sure.
1. mystery(a1 , a2 , . . . an : array of real numbers)
2. k = 1
3. bk = a1
4. for i = 2 to n
5. c = 0
6. for j = 1 to i − 1
7. c = aj + c
8. if (ai ≥ c)
9. k = k + 1
10. bk = ai
11. return b1 , b2 , . . . , bk
Here's an equivalent I tried to write in Java, but I'm not sure if I translated properly:
public int[] foo(int[] a) {
int k=1;
int nSize=10;
int[] b=new int[nSize];
b[k]=a[1];
for (int i=2;i<a.length;){
int c=0;
for (int j=1;j<i-1;)
c=a[j]+c;
if (a[i]>=c){
k=k+1;
b[k]=a[i];
Google never ceases to amaze, due on the 29th I take it? ;)
A Java translation is a good idea, once operational you'll be able to step through it to see exactly what the algorithm does if you're having problems visualizing it.
A few pointers: the psuedo code has arrays indexed 1 through n, Java's arrays are indexed 0 through length - 1. Your loops need to be modified to suit this. Also you've left the increments off your loops - i++, j++.
Making b magic constant sized isn't a good idea either - looking at the pseudo code we can see it's written to at most n - 1 times, so that would be a good starting point for its size. You can resize it to fit at the end.
Final tip, the algorithm's O(n2) timed. This is easy to determine - outer for loop runs n times, inner for loop n / 2 times, for total running time of (n * (n / 2)). The n * n dominates, which is what Big O is concerned with, making this an O(n2) algorithm.
The easiest way is to take a sample but small set of numbers and work it on paper. In your case let's take number a[] = {3,6,1,19,2}. Now we need to step through your algorithm:
Initialization:
i = 2
b[1] = 3
After Iteration 1:
i = 3
b[2] = 6
After Iteration 2:
i = 4
b[2] = 6
After Iteration 3:
i = 5
b[3] = 19
After Iteration 4:
i = 6
b[3] = 19
Result b[] = {3,6,19}
You probably can guess what it is doing.
Your code is pretty close to the pseudo code, but these are a few errors:
Your for loops are missing the increment rules: i++, j++
Java arrays are 0 based, not 1 based, so you should initialize k=0, a[0], i=1, e.t.c.
Also, this isn't sorting, more of a filtering - you get some of the elements, but in the same order.
How do I analyze stuff like this and know whats going on?
The basic technique for something like this is to hand execute it with a pencil and paper.
A more advanced technique is to decompose the code into parts, figure out what the parts do and then mentally reassemble it. (The trick is picking the boundaries for decomposing. That takes practice.)
Once you get better at it, you will start to be able to "read" the pseudo-code ... though this example is probably a bit too gnarly for most coders to handle like that.
When converting to java, be careful with array indexes, as this pseudocode seems to imply a 1-based index.
From static analysis:
a is the input and doesn't change
b is the output
k appears to be a pointer to an element of b, that will only increment in certain circumstances (so we can think of k = k+1 as meaning "the next time we write to b, we're going to write to the next element")
what does the loop in lines 6-7 accomplish? So what's the value of c?
using the previous answer then, when is line 8 true?
since lines 9-10 are only executed when line 8 is true, what does that say about the elements in the output?
Then you can start to sanity check your answer:
will all the elements of the output be set?
try running through the psuedocode with an input like [1,2,3,4] -- what would you expect the output to be?
def funct(*a)
sum = 0
a.select {|el| (el >= sum).tap { sum += el }}
end
Srsly? Who invents those homework questions?
By the way: since this is doing both a scan and a filter at the same time, and the filter depends on the scan, which language has the necessary features to express this succinctly in such a way that the sequence is only traversed once?
Related
I saw this method in a book, to do binary search, but I can't understand how it is working no matter how I try. Can someone explain to me exactly how it is working?
the book's explanation did not help :
The idea is to make jumps and slow the speed when we get closer to the
target element.
The variables k and b contain the position in the array and the jump
length. If the array contains the element x , the position of x will
be in the variable k after the search. The time complexity of the
algorithm is O (log n ), because the code in the while loop is
performed at most twice for each jump length.
what I don't get is that how is k iterating in the array? How can we make sure that it will not jump over the target's index? I tried tracing some runs of this program with sample values but couldn't figure out the pattern that k is following to find whether target x exists in the array or not.
int k = 1;
for (int b = n/2; b >= 1; b /= 2) {
while (k+b <= n && t[k+b] <= x) k += b;
}
if (t[k] == x) {} // x was found at index k
note: I do understand clearly the "common binary search algorithm" (the one that uses start, middle, and end indices )
b are the length of the jumps of your current position. As you can see, b starts as n/2 and is divided by 2 at each step up until it reaches 1.
Now, For each b, remember that b is divided by 2 at each step in the for loop, we run a while loop where we add b to to our current position, which is k. We add b to k checking for 2 conditions: k+b is less than n (to make sure we don't go out of bounds), and t[k+b] is less than x, which we are searching.
This effectively means that for each b, we add b to k up until where it would go over the value we are seeking. At this point, the while loop breaks and we divide b to approach slower to the target hoping we don't go over it.
The final b is just one, to make sure we don't miss x if it is just the next element after the position of k.
Look at it this way, a car is racing towards a goal. At first the car is going maximum speed, as it nears the target, it gradually decelerates up until it reaches the target.
The difference with traditional binary search, which makes it a little counter intuitive, is that in traditional binary search, we go over the target and then come back and go over again and in each iteration we decrease the steps that we take back and forth. In this algorithm, we only go forwards (never over the target), but we continuously decrease the length of the steps by dividing b.
consider the following snippet in cpp. This is taken from dynamic programming tutorial .
It is mainly for space optimized knapsack problem.
for(int i=1;i<=a;i++)
{
int t = a%2;
for(int j=0;j<1100000;j++) dp[t][j] = inf;
for(int j=0;j<1100000;j++){
dp[t][j] = min(dp[t][j],dp[!t][j-v[i-1]]+w[i-1]);//!t part is for skipping the current
}
}
This snippet is taken from this tutorial. I want to convert this technique into java. But java does not support this type of integer manipulation. Please can anyone explain me how it works and appropriate conversion to java ? thanks.
Just replace !t with t ^ 1 or 1 - t (whatever you find more readable; the effect is the same). That's all you need to do here.
Explanation
Java supports all the integer manipulation on display in this snippet:
int t = a % 2; <-- this is valid java and means the same thing in java as it does in C: divide a by 2, and put the remainder in t, preserving the sign of a. Thus: t is now 0 if a was even, and 1 if a was positive and odd, and -1 if a was negative and odd. It looks like a is supposed to be positive in this scenario, meaning that t can only be 0 or 1 here.
dp[t][j] <-- valid java. Declare dp as for example int[][] dp = new int[100][100];.
min(someExpression, someOtherExpression) <-- valid java; add import static java.lang.Math.min; or replace min with Math.min to make it work.
dp[!t] <-- the !t isn't valid java; but, in C, running !t where t is either 0 or 1 is just flipping things: If t is 1, !t is 0, and vice versa. And that you can trivially do in java: Use t ^ 1 or 1 - t or even t == 0 ? 1 : 0 – all have the exact same behaviour and are valid java.
So I'm trying to write code for a modified version of the rod cutting problem. The link gives a good intuition of the problem. However, I want to modify the code to not only actually return the solution, i.e. what cuts give the optimal solution, but also limit the number of cuts to a maximum of k.
For proof of concept, I'm trying to create an algorithm to achieve this. The following is what I have so far, I think it successfully returns the actual solution, however, I can't figure out how to limit the maximum to k.
let r[0..n] be a new array
r[0] = 0
for j = 1 to n
q = -1
for i = 1 to j
for k = 0 to n-1
q = Math.max(q[n][k], p[i] + q[n-i-1][k-1]);
r[j] = q
return r[n]
Please do not provide with actual code in your answers, I want to implement that myself, I just need help tweaking my algorithm to give the correct solution.
Update 1: I am already able to find optimal solution for a maximum of k cuts by adding a second dimension to my array. This is shown in the above code.
As you say, you already have the optimal solution, this answer includes only how to retrace the exact solution (cuts made at each step).
Store the candidate cut for length = n and maximum cuts = k
For this, you simply need a 2-d array (say, visit[n][k]) to store the cut made that gets the maximum solution to q[n][k]. In terms of pseudo code and recurrence relations, it will look like the following.
for each value of i:
q[n][k] = q[n][k-1]
visit[n][k] = -1
if q[n][k] < p[i] + q[n-i-1][k-1]:
q[n][k] = p[i] + q[n-i-1][k-1]
visit[n][k] = i
Explanation
It is possible that we don't have a cut that maximizes the solution. In this case, we initialize visit[n][k] = -1.
Every time, we have a candidate to cut the rod of length n at length=i+1, ie. we could get a better price by a cut, we will store the respective cut in another 2-d array.
Reconstruct the solution
Using this 2-d array (visit[n][k]), to back trace the exact cuts, you can use the following pseudo code (I am deliberately avoiding code since you mentioned you don't need it).
cuts = []
while k > 0:
i = visit[n][k]
if i != -1
// If there is a cut
cuts.push(i + 1)
n = n - i - 1
k = k - 1
Explanation
We iterate from k to 0.
Every time, when visit[n][k] is not -1, ie. it is optimal to cut somewhere, we reassign n after making the cut, ie. n = n - i - 1 and store the resultant cut in the array cuts.
Finally, cuts will contain the exact cuts that led to the optimal solution.
Please note that the pseudo code present in your question is slightly incorrect in terms of variables used in the recurrence relation. q is used both to store the DP 2-d array as well as an integer -1. j is not used in the bottom-up DP at all and is replaced with constant n. q[j][k] is uninitialized. However, the general idea is correct.
For an assignment I've been given some stuff to do involving FORTRAN code, but the only issue is that we haven't been taught it yet so I'm not entirely sure what's going on so I've attempted to convert it to Java to try get a grasp on it. The following is the FORTRAN code:
L1: DO 20 I = 1, 512
L2: SUM(I) = 0
L3: DO 40 J = 1, I
L4: 40 SUM(I) = SUM(I) + 1
L5: 20 CONTINUE
The idea is that L2 and L4 both take a machine cycle and I have to work out how long it takes for the loop to complete. The following is my Java which I think is at least reasonably close to working out the value I want:
public static void main(String[] args) {
int cycles = 0;
for(int i = 1; i < 512; i++){
cycles = cycles + 1;
for(int j = 1; j < i; j++){
cycles = cycles +1;
}
}
System.out.println(cycles);
}
Does this seem correct? Any help is appreciated. I've thought through it mathematically and got a different answer (although both are close to each other) so I'm not sure which is better.
EDIT: I'd like to make clear that I'm not attempting to port the FORTRAN directly to Java, rather just calculate the cycle time mentioned above by using Java.
EDIT 2: I'm not trying to create the Array, only calculate the cycles taken during the loops. Because both lines L2 and L4 take a cycle, I've swapped it in the Java ONLY to figure out the cycles taken, not do what the FORTRAN loop does.
In the Fortran the statement
DO 20 I = 1, 512
starts a loop whose end is the line with label 20. Similarly, the inner loop ends on the statement labelled 40. In modern Fortran this might look like
DO I = 1, 512
SUM(I) = 0
DO J = 1, I
SUM(I) = SUM(I) + 1
END DO
END DO
or even, since Fortran (since Fortran 90) has array statements and, as Duffymo has observed, SUM is an array
DO I = 1, 512
SUM(I) = I
END DO
or, as I would write it, using an array constructor with an implied do loop:
SUM = [(I,I=1,512)]
The Fortran sets element Iof SUM to I.
So, to answer OP's question more directly, the original Fortran code executes line 2 512 times and line 4 1+2+3+4+...+512 times.
My opinion is that writing a Java (or indeed any language) program to compute this sum is exactly the sort of thing that students of computer science (or software engineering or ...) should be taught not to do; there is a well-known closed-form equation for the sum of the first N integers (italicised to clarify what the term you should be Googling for is) and any aspiring software developer ought to know this closed-form. Such an aspirant ought to know this closed-form precisely to be able to figure out how many operations are invoked in loops such as the ones shown without having to write a program to iterate pointlessly.
To conclude, OP's Java program would get an F- on any course I taught because it is not an implementation of what ought to have been implemented - a function to calculate the sum of the first N integers. That F- would be applied irrespective of the correctness or otherwise of the program. Since I'm not a teacher that's not much of a threat, but I simply wouldn't hire anyone pretending to be a software engineer without this knowledge.
I'm currently studying for my introductory CS final, and I'm having a really rough time with a few problems. The one I'm most worried about asks me to produce the code, in Java, to create the following output to the screen:
+
+++0
++++++00
++++++++++000
... (this pattern continues for 200 lines)
This might seem like a very basic question, but how do I go about doing this? I know that I should write some arrays and use for loops to go through them and output stuff to the screen, but I would really appreciate some guidance on how to solve this problem, along with others of its ilk. Thanks!
The pattern for the number of 0 is simply an arithmetic sequence. The number of + is as follows:
Row 1: 1
Row 2: 3 = 1 + 2
Row 3: 6 = 3 + 3
Row 4: 10 = 6 + 4
Turns out that these are triangular numbers. So, calculate the triangular number for each row in a loop, and have a nested loop that prints + that many times, then print the required number of 0.
I don't think this deserves a -1. Beginner question is not equal to a bad question.
As for the question itself. You have to carefully identify the pattern first and then word it in plain English. The pattern is quite simple.
Start with 1 cross and 0 zero. For each iteration, increase the growth
of crosses by 1 (so it's +1, +2, +3...) starting with a growth of 2
units and increase the growth of zeroes by 1 starting at 1 unit.
Now put this into pseudo-code and then code it. Be sure to understand the patterns first. I cannot stress this enough. Going right into coding will not help you.
First you need to be able to recogonize the pattern, then you need to be able to code it.
I'm going to go out on a limb and suggest that you are mixing the two "steps" of this problem together, so let's be very specific in dividing them.
The (parenthesis) items are the _additional_ elements.
index 0 : +
index 1 : +(++)(0)
index 2 : +++(+++)0(0)
index 3 : ++++++(++++)00(0)
so a good guess is that the pattern could be described as:
the previous number of +'s (and index + 1 more),
followed by the previous number of 0's (and one more).
combined with
index 0 is "+"
You might want to calculate index 4, 5, and 6 from this "rule" and see if it seems to describe the pattern correctly.
Now that you have the pattern, you really only need two variables, the number of + signs, and the number of 0s. You can calculate the "next" one from the previous one. The coding shouldn't be too hard, but if it is, then post your program and your "new" problem with that program in another question.
public class Answer {
public static void main(String[] args) {
int plusCount = 1;
for(int i=0; i<200; i++) {
for(int j=0; j<plusCount; j++) {
System.out.write('+');
}
plusCount += i+2;
for(int j=0; j<i; j++) {
System.out.write('0');
}
System.out.println();
}
}
}