2010-10-28, 04:38 AM (This post was last modified: 2010-10-28, 12:24 PM by Kalovale.)
Well, I'm thinking I should form a good coding habit from the beginning. There is almost no complexity in these problems, but I feel that there are better ways to write the codes, or even more condensed logical approaches. So, if you're bored, would you kindly show me how you'd tackle these problems, I'll figure out the details on my own.
Current issue: I think I'm using if-else-then statements too excessively.
codingbat:
Logic:
1/
Spoiler
[COLOR="red"]We want to make a row of bricks that is goal inches long. We have a number of small bricks (1 inch each) and big bricks (5 inches each). Return true if it is possible to make the goal by choosing from the given bricks. This is a little harder than it looks and can be done without any loops.
[COLOR="red"]Given 3 int values, a b c, return their sum. However, if one of the values is the same as another of the values, it does not count towards the sum.
[COLOR="red"]Given 3 int values, a b c, return their sum. However, if one of the values is 13 then it does not count towards the sum and values to its right do not count. So for example, if b is 13, then both b and c do not count.
public int luckySum(int a, int b, int c) {
if(a==13){return 0;}
else{if(b==13){return a;}
else{if(c==13){return a+b;}
else{return a+b+c;}}}
}
4/
Spoiler
[COLOR="red"]Given three ints, a b c, return true if one of b or c is "close" (differing from a by at most 1), while the other is "far", differing from both other values by 2 or more. Note: Math.abs(num) computes the absolute value of a number.
I don't think you're using too many if statements. When trying to find code bloat, the easiest way to approach it is to ask if you're accomplishing anything outside of what the function definition says. I don't see that here, therefore no bloat.
However, there are likely faster algorithms. The first algorithm I'd like to look at is #2. If I were to look at this formula for the first time, I would have NO IDEA what it's supposed to do. The best code is code which documents itself. And that is not self-documenting code.
In this problem, there are four possible pairings which would cause exceptions. Either the first and second number, second and third, or third and first are alike. Each of the following if statements checks if the others are pairs.
Code:
public int loneSum(int a, int b, int c) {
int sum = 0;
Actually that was the one I had most half-heartedness in. I guess you can tell by the impropriety/inconsistency.
Anyway, how exactly do I read that operator? Exclusive OR would translate to:
"If only either a or b is greater than 0 and if only either a or c is greater than 0" ? Doesn't really sound right.
It seems what you're doing there says: "if a is not equal to b and if a is not equal to c; increment sum by a"
Okay this is getting pretty petty of me, but I keep getting the impression that my approach isn't proper enough. It just seems somehow messy.
Spoiler
[COLOR="red"]Given three ints, a b c, return true if one of b or c is "close" (differing from a by at most 1), while the other is "far", differing from both other values by 2 or more. Note: Math.abs(num) computes the absolute value of a number.
Quote:Given 3 int values, a b c, return their sum. However, if any of the values is a teen -- in the range 13..19 inclusive -- then that value counts as 0, except 15 and 16 do not count as a teens. Write a separate helper "public int fixTeen(int n) {"that takes in an int value and returns that value fixed for the teen rule. In this way, you avoid repeating the teen code 3 times (i.e. "decomposition"). Define the helper below and at the same indent level as the main noTeenSum().
The solution should be simple enough, but I can't seem to "call" the n from the fixTeen block to the main block to use. Also, I may not be thinking straight but how do I filter so that the outcome n satisfies certain conditions? I have been doing something along the lines of conditionals:
Code:
public int fixTeen(int n){
if( (n>=13) && (n<=19) && (n != 15) && (n != 16) )
return n;
}
But I can't test if it works correctly because of the problem above.
2010-10-28, 12:49 PM (This post was last modified: 2010-10-28, 03:07 PM by Nikkey.)
Fiel Wrote:In this problem, there are four possible pairings which would cause exceptions. Either the first and second number, second and third, or third and first are alike. Each of the following if statements checks if the others are pairs.
Spoiler
Code:
public int loneSum(int a, int b, int c) {
int sum = 0;
I'm sure there must be a faster way to do this as well because b^a is the same as a^b.
I see no reason as of why you need to xor first, then compare with >. This works perfectly fine, does the same thing and requires less computing power:
Spoiler
Code:
public int loneSum(int a, int b, int c) {
int sum = 0;
if(a!=b && a!=c)
sum += a;
if(b!=a && b!=c)
sum += b;
if(c!=a && c!=b)
sum += c;
return sum;
}
Faster approach is probably
Spoiler
Code:
public static int loneSum(int a, int b, int c) { // Sums up the numbers which does not equal to another number.
return a + b + c
+ (a==b?1:0) & (b==c?1:0) * a
- (a==b?1:0) | (a==c?1:0) * a << 1
- (b==c?1:0) * c << 1;
}
Since Java doesn't have proper low-level-code when coming to == > != < <= >=, I use fecking ternary.
Nevetheless, looks pretty ugly. Should use the most understandable loneSum.
For four, split it up more. You know you use repetitive patterns (diffAB <= 1), for example. Also, (! (diffAB <= 1)) == (diffAB >= 2).
Spoiler
Code:
public boolean closeFar(int a, int b, int c) {
boolean closeAB = isClose(a, b),
closeAC = isClose(a, c),
closeBC = isClose(b, c);
if (closeAB)
return (closeAC == closeBC && !closeAC);
else // We know that closeAB has to be false to get here, therefore closeAC and closeBC has to be different in order for this to produce the right answer.
return (closeAC != closeBC);
}
public boolean isClose(int a, int b){
return (Math.abs(a-b) <= 1);
}
Kalovale Wrote:Okay this is getting pretty petty of me, but I keep getting the impression that my approach isn't proper enough. It just seems somehow messy.
Spoiler
I have a favor though, regarding this problem:
The solution should be simple enough, but I can't seem to "call" the n from the fixTeen block to the main block to use. Also, I may not be thinking straight but how do I filter so that the outcome n satisfies certain conditions? I have been doing something along the lines of conditionals:
Code:
public int fixTeen(int n){
if( (n>=13) && (n<=19) && (n != 15) && (n != 16) )
return n;
}
But I can't test if it works correctly because of the problem above.
As of right now, fixTeen returns n if n is 13, 14, 17, 18 or 19. Otherwise, what does it return? What should it return?
Devil's Sunrise Wrote:As of right now, fixTeen returns n if n is 13, 14, 17, 18 or 19. Otherwise, what does it return? What should it return?
I expect it to return exactly those values, as for the "else" part, that's what perplexes me. I want to filter out the non-teen values with a view that after the method, n consists of only teens.
Kalovale Wrote:I expect it to return exactly those values, as for the "else" part, that's what perplexes me. I want to filter out the non-teen values with a view that after the method, n consists of only teens.
I feel more accomplished with this than with #4, but aside from sorting out all the special cases one by one, I can't think of another approach. Any suggestions/evaluations? I don't mean to be studying things I'm not supposed to. I'm just thinking there might be a fundamental technique that I missed from reading the guides.
Also, is it noticeably bad practice to create unnecessary objects? Like the remainder below with is only used once and can easily be substituted by goal%5?
Spoiler
[COLOR="red"]We want make a package of goal kilos of chocolate. We have small bars (1 kilo each) and big bars (5 kilos each). Return the number of small bars to use, assuming we always use big bars before small bars. Return -1 if it can't be done.
Kalovale Wrote:Also, is it noticeably bad practice to create unnecessary objects? Like the remainder below with is only used once and can easily be substituted by goal%5?
Not at all, in fact the opposite is true. Using variables to store intermediate results can make your code more readable than if you have one gigantic expression.
Something you'll learn down the road is that maintainable code is worth far, far more than fast code. Eventually down the line someone else is going to look at your code. It might even end up on TDwtp (lol - the daily wt'f - just google it). Fast code is only necessary when one needs bal'ls to the walls speed, and for many applications it's simply not necessary.
The best code is "at-a-glance" code where you can just skim it and have a fairly good idea of exactly what each method or function will do.
Good coding practices state that about 15 - 20% of your code should be developer comments. More complicated parts of the code should be documented heavier. Comments should not restate the code, but state why that method of code was used instead of another, or explain the purpose of the code at hand.
Kalovale Wrote:I feel more accomplished with this than with #4, but aside from sorting out all the special cases one by one, I can't think of another approach. Any suggestions/evaluations? I don't mean to be studying things I'm not supposed to. I'm just thinking there might be a fundamental technique that I missed from reading the guides.
Also, is it noticeably bad practice to create unnecessary objects? Like the remainder below with is only used once and can easily be substituted by goal%5?
Spoiler
[COLOR="red"]We want make a package of goal kilos of chocolate. We have small bars (1 kilo each) and big bars (5 kilos each). Return the number of small bars to use, assuming we always use big bars before small bars. Return -1 if it can't be done.
To me, if the question implies an ordering to the process, it's better if the code mimics that process. Start by subtracting as many large chocolate bars as possible from the total, then consider whether the small ones are enough to fit the remainder. If you separate the two steps like that, it makes it easier to read what's happening than if you calculate a few numbers at the start, then compare them and spit out a result.
In this case, you want to subtract either
a) all the large chocolate
b) as many large chocolates as fit in the total
Depends which is smaller.
-- a is easy to calculate, it's just 'big'
-- b is total/5
So,
Code:
// remove as many big chocolates as possible, while leaving total positive
if (total/5 < big)
total = total%5;
else
total = total - 5*big;
Then compare the remaining total to the number of small chocolates you have available.
Code:
// return the number of small chocolates necessary to make up the total
if (small >= total)
return total;
else
return -1;
By doing it this way I've also reduced your 4 if conditions to 2.
To me, if the question implies an ordering to the process, it's better if the code mimics that process. Start by subtracting as many large chocolate bars as possible from the total, then consider whether the small ones are enough to fit the remainder. If you separate the two steps like that, it makes it easier to read what's happening than if you calculate a few numbers at the start, then compare them and spit out a result.
In this case, you want to subtract either
a) all the large chocolate
b) as many large chocolates as fit in the total
Depends which is smaller.
-- a is easy to calculate, it's just 'big'
-- b is total/5
So,
Code:
// remove as many big chocolates as possible, while leaving total positive
if (total/5 < big)
total = total%5;
else
total = total - 5*big;
Then compare the remaining total to the number of small chocolates you have available.
Code:
// return the number of small chocolates necessary to make up the total
if (small >= total)
return total;
else
return -1;
By doing it this way I've also reduced your 4 if conditions to 2.
I forgot at the time I could manipulate the arithmetics like that. I was rather thinking in the mindset of "returning value X if satisfying condition Y", not "transforming X to Y under condition Z". Thanks.
Now I'm totally stuck here. ;-;
EDIT: I got an idea, lemme try it out.
Spoiler
5/
Spoiler
[COLOR="red"]Given a non-negative int n, return the count of the occurrences of 7 as a digit, so for example 717 yields 2. (no loops). Note that mod (%) by 10 yields the rightmost digit (126 % 10 is 6), while divide (/) by 10 removes the rightmost digit (126 / 10 is 12).
public int count7(int n) {
int count = 0;
int remainder = n%10;
if(remainder == 7) { // if find 7
count++; // increment count
n = count7(n/10); // continue checking the next digit -- This is where I'm wrong, it just doesn't work
}
else {
if(n>10) { // if still divisible by 10
n = count7(n/10); // proceed to check the next digit, through the procedure applied above.
} // Keep repeating until the condition is exhausted
else count = 0; // exhausted, found zero 7
}
return count;
}
I think I'm not applying a brake here for the recursion to end when it's done checking the left-most digit. I dunno how though.
Okay, I think I know. From working out a similar problem.
6/
Spoiler
[COLOR="red"]Given a positive int n, return true if it contains a 1 digit. Note: use % to get the rightmost digit, and / to discard the rightmost digit.
public boolean hasOne(int n) {
boolean result = false;
if(n%10 == 1) {
result = true;
}
else {
if(n>=1) {
result = hasOne(n/10);
}
else result = false;
}
return result;
}
Nevermind, I have no idea at all. In problem 6, once it returns true, it doesn't have to continue checking like when it finds a 7 in problem 5.
I think my brain exploded. Calling count7(n/10) is finding the count of 7's in the input n/10, not putting n/10 through the process of checking for 7's... If I call for a recursion on a method at halfway through it, does it evaluate up to that point, or the whole method?