I have recently been reading Sedgewick's Algorithms Book, and I came across an example I didn't quite understand...
Using this code, Sedgewick mentions that the if statement is run precisely
N x (N-1)(N-2)/6 times.
I don't quite understand why that is.... I see that there are the triple nested loops, each with an upper bound that is increasing, but why is the value divided by six?
I ask for your understanding that I am not good at math, so the explanation may be a little bit cheesy.
In order to 'if(a[i] + j[i] + k[i]) statement' inside the code be executed The variables i, j, and k that point out an array 'a' index in Tripple for loop must fit the condition of the statement (0<= i <j<k <N), right?
For example, N is 4.
It seems to be available through the permutation (4P3 = 4^3) that selects three of the four, but if 4 is selected in 'i' as shown in the picture above, you can see that progress is blocked in 'j' for-loop (j = 4+1; j<4; j++).
So We can't get the number of times an if statement will run with a simple sequence.
What we need is a combination (nCr).
When index flows from 0 to N-1,
The number of cases (i,j,k) that satisfy i < j < k(=> if statement can run) can be obtained by the formula nC3.
According to this formula, if statement is run precisely N x (N-1)(N-2)/6 times
I hope you understand it well and if you don't, please leave a comment!
Have a nice day!
Related
I recently worked on an online problem for which answers were not provided, however, I would like to know where I went wrong. The prompt was strange, but I will do my best to explain it:
There is a machine that can fix all potholes along a road 3 units in length. A unit of Road will be represented with a period in a String. For example, "..." = one section of road 3 units in length. Potholes are marked with an "X" in the road, and also count as a unit of length. The task is to take a road of length N and fix all potholes with the fewest possible sections repaired by the machine. This problem is concerned with performance over correctness.
Example 1: A road represented by ".X." would require 1 fix.
Example 2: A road represented by "..X...X" would require 2 fixes.
Example 3: A road represented by "XXX.XXXX" would require 3 fixes.
My approach (shown below) was to count sections of String in increments of 3 chars at once. If that sequence contained an "X", then it needed a fix and vice versa. To account for roads that aren't multiples of 3 in length I just kept the sequence reading and checked whatever was left. I'm also not sure how to make the program better for performance (other than replacing my sequence String with a StringBuilder)
public class Solution {
//Note: I had to re-write this from memory, as I was not given it back by the online problem checker
public int solution(String S) {
int fixes = 0;
String sequence = "";//Perhaps use StringBuilder?
for (int i = 0; i < S.length(); i++) {//read the entire incoming string
for (int j = 0; j < 3; j++) {//Count 3 chars at once
sequence += S.charAt(i);//Add said Chars to our sequence
}
if (sequence.contains("X")) {//Check for potholes
fixes++;//We can fix everything in this sequence
sequence = "";//reset our sequence
}
}
if (sequence.contains("X")) {//Check anything left, since not all roads are multiples of 3
fixes++;
}
return fixes;
}
}
I thought this was good enough for what was asked, and it passed all of the given example Strings, but apparently failed horribly upon review. I don't know what I've done wrong, though I feel like there's probably something small and stupid that I'm missing.
UPDATE:
I was indeed missing something obvious, I need to start reading at the first "X", something like this:
if (S.charAt(i) == 'X') {//Start counting at the first X
for (int j = 0; j < 3; j++) {//Count 3 chars at once
if (i + j <= S.length() - 1) {//no outofbounds exceptions please!
sequence += S.charAt(i + j);//Add said Chars to our sequence
}
}
}
Now I just need to make sure it meets performance requirements.
and it passed all of the given example Strings
But... how?
Your code is completely wrong. How can it have passed the example strings? Must have been some very unlucky examples, then!
for (int j = 0; j < 3; j++) {//Count 3 chars at once
sequence += S.charAt(i);//Add said Chars to our sequence
}
This will add the exact same character, 3 times. i never changes. Thus, sequence is either "..." or "XXX".
if (sequence.contains("X")) {//Check for potholes
fixes++;//We can fix everything in this sequence
sequence = "";//reset our sequence
}
This boils down to: If it was "XXX", increment fixes.
if (sequence.contains("X")) {//Check anything left, since not all roads are multiples of 3
fixes++;
}
This if cannot possibly trigger. Think about it.
All your code does, is count potholes. In a convoluted way.
I thought this was good enough for what was asked
You've made 3 major errors. Each is individually probably sufficient to get a significant downgrade if this is an exercise for a job:
The code contains a performance faux-pas (concatenating strings using + in a loop), when the question explicitly calls out that performance is important. You'd have to call it out and explain why you intentionally broke a rule of thumb, at least.
The code straight up doesn't work, at all.
Even if you fix it, the code STILL does not work. Take, for example, the input ".X.X..". The correct answer is 1. Even if you fixed your code and you treat each chunk of 3 properly (instead of one at a time due to your messup between j and i), your algorithm returns 2. The question is a little more complicated than you think it is. Not much, mind. Still, the entire algorithm as written should just be tossed in the bin, and start over. Don't start with programming. Start with schetching out the problem and considering the algorithm required. Only then start coding.
Here is the correct algorithm. Just sketched out, thinking the problem through:
Just scan for a pothole. Once you find one, fix it and skip past the next 2 units of road while you're at it. They just do not matter. If they have potholes, we'll fix em for free along with the hole we found.
That's all you need to do. Just count potholes, ignoring any potholes that are 1 or 2 'to the right' of a pothole we fixed.
Here:
public int solution(String s) {
int holes = 0;
for (int i = 0; i < s.length(); i++)
if (s.charAt(i) == 'X') {
holes++;
i += 2;
}
}
return holes;
}
This code is much simpler, is correct, and is clearly as fast as it's ever gonna get.
Segmenting the string into groups of 3 will fail when potholes don't align with those divisions. Sometimes it will be optimal for the machine to skip 1 or 2 units, or 4 or 5 -- some number that isn't a multiple of 3.
For example, consider this road:
.X.XX.XX.X
Your algorithm will declare that 4 segments need to be repaired:
|.X.|XX.|XX.|X|
But it can be done in 3 segments:
.|X.X|X.X|X.X|
Your program only reads the road in sections of 3 units. It can give a wrong answer for some configurations.
For instance, it will answer "2" for ..X.X...., while this road can be fixed in only one fix.
It will read ..X, .X., ..., when it should read up until the first X, forget what was before, and then do a fix of 3 units before continuing.
It should read .., X.X, ....
def pothole_fixing(road):
potholes = 0
sections = 0
for i in range(len(road)):
if road[i] == 'X':
potholes += 1
else:
if potholes > 0:
sections += -(-potholes // 3)
potholes = 0
if potholes > 0:
sections += -(-potholes // 3)
return(sections)
The function takes a string road representing the road with potholes and returns the minimum number of sections needed to fix all potholes.
Explanation
I was given a task in my Grade 12 Computer Science class that just totally has me stumped. So far I have tried using a bunch of if statements (While i know that is not the best way of doing I though for sure it was going to work) but that didn't work. I then tried to use nested loops but that didn't work either here is the code that I created so far for this method.
Code (Note: Max=1000)
private static void totals2 (Scanner user_input,int max){
int[] num = new int[max];
int[] total=new int[10];
System.out.println("Welcome to totals\nThis method gathers input and displays the sum depending on which category they fall in");
System.out.println("Enter numbers from 0-99 only (Up to 1000 inputs)\nEnter any number outside of 0-99 to stop collecting\n");
for (int i = 0; i < num.length; i++) {
System.out.println("Please enter a number to be stored in index: " + i);
num[i] = user_input.nextInt();
if (num[i] < 0 || num[i] > 99) {
break;
}
}
for(int i = 0; i < 100; i +=10){
int j;
int k=(i/10)-1;
for(j=0 ;j<1000;j++){
if (num[j] <= i){
total[k]+= num[j];
}
}
System.out.println(total[k]);
}
}
Question
Create a procedure that will output the total of all numbers (in an array) entered less than 10, the total of all numbers entered less than 20, the total of all numbers entered less than 30, ... and the total of all numbers entered less than 100 (so 88 will be included in both totals for numbers less than 90 and less than 100).
As it is your assignment, I will not post any code here. Just some thoughts.
Do you need to save the number out of 0 to 99? If not, check your first loop.
for your second for loop, if i=0, what value will be k? if i=10 what value will be k?
I did not run your algo, that's all issues I found while reading it. Learn how to use a debugging tool will be helpful for your further study. (Recommend Intellj for Java development)
Great first question:
This already has answers for your problems, normally your question would probably get closed as a duplicate of these, but I think it should be left open so you can get some details about your code since you did such a good job with your first question.
Since you are pretty close to getting this correct I am just going to say that everything you need to get your code working is in the two questions linked below.
How to use Scanner properly:
How to use java.util.Scanner to correctly read user input from System.in and act on it?
How to iterate over an Array:
How to avoid ArrayIndexOutOfBoundsException or IndexOutOfBoundsException?
Effectively Debugging:
What is a debugger and how can it help me diagnose problems?
What is a stack trace, and how can I use it to debug my application errors?
First off, you can not iterate through an Array with integer index values greater than the number of indexes (- 1 because arrays are zero (0) based) contained within the Array otherwise you will simply end up with an ArrayIndexOutOfBoundsException. If there are only 20 elements contained within the Array then you can only iterate from 0 to 19....not 0 to 999. With this in mind, change 1000 to num.length and you should be fine with the exception of....
For your for loop used to increment by 10 for the "find values less than" value, initialize the variable i to 10 instead of 0. Think about it...do the math...what do you think will happen when you try to divide 0 into 10 then subtract 1 [(0 / 10) - 1]? You end up with an invalid index value for the variable k and therefore, another ArrayIndexOutOfBoundsException.
Also, if you read the question carefully you can see that what is required are the sums of values supplied that are less than 10, less than 20, less than 30....less than 100. Not Less Than or Equal To (... <= ...). Correct your if statement condition within your second for loop.
Food for thought:
You might want to ask the User to supply the max array index value as
well and eliminate that as a parameter for the totals2() method. Place the explanation for it into the "Welcome" message.
A Big O notation question...What is the Big O for the following code:
for (int i = n; i > 0; i = i / 2){
for (int j = 0; j < n; j++){
for (int k = 0; k < n; k++){
count++;
}
}
}
My Thoughts:
So breaking it down, I think the outside loop is O(log2(n)), then each of the inner loops is O(n) which would result in O(n^2 * log2(n)) Question #1 is that correct?
Question #2:
when combining nested loops is it always just as simple as multiply the Big O of each loop?
When loop counters do not depend on one another, it's always possible to work from the inside outward.
The innermost loop always takes time O(n), because it loops n times regardless of the values of j and i.
When the second loop runs, it runs for O(n) iterations, on each iteration doing O(n) work to run the innermost loop. This takes time O(n2).
Finally, when the outer loop runs, it does O(n2) work per iteration. It also runs for O(log n) iterations, since it runs equal to the number of times you have to divide n by two before you reach 1. Consequently, the total work is O(n2 log n).
In general, you cannot just multiply loops together, since their bounds might depend on one another. In this case, though, since there is no dependency, the runtimes can just be multiplied. Hopefully the above reasoning sheds some light on why this is - it's because if you work from the inside out thinking about how much work each loop does and how many times it does it, the runtimes end up getting multiplied together.
Hope this helps!
Yes, this is correct: the outer loop is logN, the other two are N each, for the total of O(N^2*LogN)
In the simple cases, yes. In more complex cases, when loop indexes start at numbers indicated by other indexes, the calculations are more complex.
To answer this slightly (note: slightly) more formally, say T(n) is the time (or number of operations) required to complete the algorithm. Then, for the outer loop, T(n) = log n*T2(n), where T2(n) is the number of operations inside the loop (ignoring any constants). Similarly, T2(n) = n*T3(n) = n*n.
Then, use the following theorem:
If f1(n) = O(g1(n)) and f2(n) = O(g2(n)), then f1(n)×f2(n) = O(g1(n)×g2(n))
(source and proof)
This leaves us with T(n) = O(n2logn).
"Combining nested loops" is just an application of this theorem. The trouble can be in figuring out exactly how many operations each loop uses, which in this case is simple.
You can proceed formally using Sigma Notation, to faithfully imitate your loops:
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();
}
}
}
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?