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.
Related
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!
I just wanted to start by saying that I have been searching though this (and a few other) site for the last 3 hours to no avail, i have read every post i could find in regards to my topic and either it did not apply or i couldn't quite understand what was happening.
I'm having 2 issues.
I can't seem to get the random number generator to discard a choice once it has been made.
My second issue is that there can only be one six point round per competition, and i cant seem to figure out how to limit it only to one with the specific constraints of a 6 point round.
The program is designed to simulate picking the jumps for a
skydiving competition. There are three separate competitions
(A,AA,AAA) (levels of difficulty, certain moves do not appear A or
AA, AAA is all inclusive) that the user can pick from as well as
whether the individual competition will be 6 or 10 rounds (A will
always be 6 rounds). Once the user has picked the competition and
number of rounds, the program is supposed to output the individual
moves to be completed for each round as well as the points for the
round (does this for all 6 or 10 rounds of the competition). Here is
where my first issue lies:
Once a move is picked, it cannot be
used again for the rest of the competition. I cannot for the
life of me figure out how to do this.
Moving on, there are two
separate categories for scoring, the numbered moves (1-22 in my
program) and the lettered moves (23 and up), the numbered are worth
2 points and the lettered are worth 1. each round is 5 or 6 points
The issue i am having with this is for there to be a 6 point round, it can only be made up of 3 numbered moves, no other
combination would be acceptable; and to add to that, there can only
be one six point round in the entirety of the competition.*
for(int i=0; i < round; i++ )
{
System.out.printf("\nRound %d:\n", i+1);
point = 0;
while(point < 5)
{
pickedRandom=false;
formation = myRandom.nextInt(38) + 1;
while(formation == 31)
{
formation = myRandom.nextInt(38) + 1;
}
if(point == 4 && pickedRandom && formation < 23 )
{
while(formation < 23)
formation = myRandom.nextInt(38) + 1;
}
if(formation < 23)
{
point+=2;
}
else
{
pickedRandom=true;
point++;
}
formationRound.set( formation, true );
if(formation > 22)
System.out.printf(" %s %s ",randomLetter(formation), formationName(formation));
else
System.out.printf(" %d %s", formation, formationName(formation));
}
System.out.println();
System.out.printf( " %s \n", point );
}
}
I don't understand your question due to formatting, your problem domain, or your code.
However I think you state you want to randomize some numbers, without replacements.
Some strategies to do so are:
Create a list of numbers, then shuffle it, pop a number off each time you need a random number, until your 'deck' is empty.
Maintain a set of numbers that have already been drawn. if the number is in the set, randomize another.
The lazy/brute force method of matching the 6 point round constraint would be to build your formations + competition in advance, in it's entirety. Check to see if it matches your constraints, if not, regenerate the whole competition.
This is only really economical in terms of performance if the chances of your constraints being invalid are fairly low. < 30-40%
Otherwise, you could regenerate only the current formation, but you would need to check that there are still possible valid formations remaining. I'm also not sure how badly this would affect your distribution of random formations.
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();
}
}
}
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
Hi i am doing my coursework and i have been given the task is to make an algorithm for a square that's 5x5 using "*" but has to be filled in with "." so like this:
*****
*...*
*...*
*...*
*****
I have used this code I know its probably very messy because im an absolute beginner to this stuff. I cant seem to get the "." in i currently have:
*****
*****
*****
*****
*****
here is my code:
public static void main( String args[] )
{
System.out.print ("#size of square");
int stars=BIO.getInt();
int j=1;
while(j <= stars)
{
int starsNumber=1;
while (starsNumber<= stars)
{
int i = 1; // Display trunk
starsNumber=starsNumber+1;
System.out.print('*');
}
System.out.println();
j= j +1;
}
}
p.s sorry for been so bad at coding :D and any help would be much appreciated thanks Gareth
Guidance rather than an answer since it's coursework...
It sounds like you need an if statement to decide whether to print * or .. The * should be printed when you are on the first line or the last line, or at the first column or the last column.
You will find the flow control more intuitive creating a square using a nested for loop, e.g.
for (int row=0; row<stars; row++)
{
for (int col=0; col<stars; col++)
{
// Do your output here
}
}
Have you gotten the program to print an 5x5 square full of asterisks working?
I'd strongly recommend getting that working first. After that, you just need a minor modification to print the dots in between.
For that, instead of always printing an asterisk, you'll need a conditional.
Pseudocode:
if(I'm currently on the edge)
Print an asterisk
else
Print a dot
I'll leave it to you to figure out how to translate this into real code. Good luck!
Edit, hints on how to determine if you're currently on the edge:
You are keeping track of the current row and current column (in order
to print a square exactly 5x5 characters).
The edge consists of the first and last row, and the first and last column.
Given hint 1 and hint 2, can you now determine when you are on the edge and when you're not? You'll need to do variable comparison, so read your textbook if you're not familiar with how to compare variables.
Hope that helps. There's really not much more I can say without giving away the exact answer.
Finally, think about your solution before coding it. Immediately jumping into coding can be a roadblock, especially when you're a beginner and not too familiar with the language so you get bogged down in the language syntax. Mentally put together the flow of your program, draw pictures, and maybe write pseudocode before you write the actual code. I find that doing this helps me write code easier and reduces the number of bugs that come up.
When either of your loop variables are at their limiting values (both upper and lower) you have to print a * and in other cases you have to print . Use if statement to control this flow. Cheers :)
All this "use if statement", let's do it some other way now. Of course this isn't actually useful, I just want to challenge the idea that you have to use control flow, and maybe people stumbling upon this might learn something from it..
First off, here's the code I came up with (it works)
for (int row = 0; row < stars; row++) {
for (int col = 0; col < stars; col++) {
System.out.print((char)((
(-col) >> 31 & // encodes the condition: col > 0
(-row) >> 31 &
(col - (stars - 1)) >> 31 &
(row - (stars - 1)) >> 31 & ('*' ^ '.')) ^ '*'));
}
System.out.println();
}
The basic principle I used to avoid control flow is that when a negative int is right shifted (with signed shift), the signbit is copied into the bits that are "shifted in" at the left side. A result of that is x >> 31 (where x is an int) has only two possible outcomes, 0 (if x was nonnegative) and -1 (if x was negative). You can use that principle to turn conditions into bitmasks. You can also do it with unsigned shift and a negation, but you might as well write it the shorter way.
Secondly, I used that (a ^ b) ^ a = b and a ^ 0 = a.
So when all conditions hold, '*' is xored with '*' ^ '.', giving '.', and otherwise '*' is xored with zero, giving '*'.
Of course, this is just for fun.
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?