An Array within an Array? - java

Ok so as I plod along in my classes in Java coding I was asked to use this code to count the instances of lowercase letters that were generated by a method for a character array. I can follow the code up to the point it throws out stuff like. "counts[chars[currentIndex] - 'a']++;"
So yes, the codes says it's making a public method called countLetters, it needs to be called somewhere in the main body and needs a character array parameter to fire up, got that. It creates a integer array called counts and it's size is 26, (same size as total # of lowercase letters in alphabet, got that.) It then fires up a for function, commonly needed for arrays. Creates a variable called currentIndex, default value 0, while current index is less than the size of chars character array do the stuff below. Then it gets to what the for loop actually is DOING. and uh, what the hell is it doing? it's increasing the size of count's index? The whole thing is weird, like some array within an array and subtracting the numeric value of lowercase 'a'? It's modifying the currentIndex of count somehow. Why is subtracting the numeric value of 'a' necessary? Wouldn't - 26 suffice here?
Can somebody please explain slowly and in complete layman's terms how this is working? I'm really a novice programmer at best and this stuff is confusing the hell out of me, so please bear with me, I'm not the sharpest tool in the shed, as the Smashmouth song goes. All joking aside, I'd appreciate if you could break down what is going on.
//count the occurrences of each letter
public static int[] countLetters(char[] chars){
//declare and create an array of 26 int
int[] counts = new int[26];
//for each lowercase letter in the array, count it
for (int currentIndex = 0; currentIndex < chars.length; currentIndex++)
counts[chars[currentIndex] - 'a']++;
return counts;
}

Alrightey so this line:
counts[chars[currentIndex] - 'a']++;
Is short for all of this:
// Get the current character from the array:
char character = chars[currentIndex];
// Characters are just numbers. Check out e.g. an "ASCII table".
// So, let's start treating them like numbers and take 'a' from that.
int indexInCounts = character - 'a';
// Increase the count for that letter:
counts[indexInCounts] = counts[indexInCounts] + 1;
Why 'a'?
Arrays start at 0 - you mentioned that in your question so it looks like you've got the hang of those so far. So, if we want counts[0] to represent the number of a's in the input, then we'll need to put 'a' at 0.
'a'-'a' is 0.
'b'-'a' is 1.
etc.
So, conveniently, taking away 'a' from our input character gives us a number that'll work great for our array index.
Letters taking away letters is so weird!
Computers only really deal with numbers. Pull up an ASCII table, and you get an easy way to see how letters map to the underlying numbers (in the ASCII encoding scheme):
97: Lowercase 'a'
98: Lowercase 'b'
99: Lowercase 'c'
.. And so on!
Hopefully you can see where that's going!
98 (b) - 97 (a) gives us that index of 1, for example.
Try it out, but don't forget those brackets!
If you want to experiment, you could swap out that line for the ones above, but don't forget the brackets of your for loop!
for(int a=...)
doSomething(); // Only this first line is looped
doSomethingElse(); // This happens *once*!
This is called implicit brackets and is also just a convenience thing. So, here's the full, expanded version:
for (int currentIndex = 0; currentIndex < chars.length; currentIndex++)
{
// Everything in those brackets will be repeated.
// Get the current character from the array:
char character = chars[currentIndex];
// Characters are just numbers. Check out e.g. an "ASCII table".
// So, let's start treating them like numbers and take 'a' from that.
int indexInCounts = character - 'a';
// Increase the count for that letter:
counts[indexInCounts] = counts[indexInCounts] + 1;
}
Am I supposed to write stuff like that straight away?
Not really, no! In reality, you'd typically start out with the expanded version seen above (although most would immediately use counts[indexInCounts]++;). When a variable is only used once it's often easier to then substitute the actual value in - like this, without all those comments:
char character = chars[currentIndex];
int indexInCounts = character - 'a'; // Character is only used once.
counts[indexInCounts]++; // indexInCounts is only used once.
Step 2:
char character = chars[currentIndex];
counts[character - 'a']++; // Character is only used once.
Finally, the magical line is back:
counts[chars[currentIndex] - 'a']++;
Predicting errors
If you think you've got the hang of it then try and predict what error you'll get if you chuck an evil space character into the input.
Here's a spoiler:
You'll get an index out of range exception. Space is 32 on that ASCII table. 32 - 97 is very much a negative number, and very much out of range of the acceptable 0-25 of your counts array!
P.s. I'm not the sharpest tool in the shed - I will forever and always disagree (except about the song; that's great) :) Everybody has to start somewhere and you're giving it a try so I wish you all the best!

Related

How do I reduce the number of (the same) characters printed in each line using a loop?

Basically, I am trying to print lines of characters, specifically asterisks. Every subsequent line should have one less asterisk than the previous line. Additionally, they should all be aligned to the right.
My knowledge of Java is not too strong, so bear with me.
Here's an image of the output and the instructions:
Let's start off with a simpler example:
***
**
*
What pattern do you see? The pattern is that on each line, the sum of the amount of asterisks and the amount of spaces is constant. I'll call this constant L for now on, which stands of the line length.
From this, we can infer that amountOfSpaces is L - amountOfAsterisks, and vice versa (as the magical laws of Algebra also apply here).
So from this, we can deduce that on each line we need to print L - amountOfAsterisks spaces first, and then amountOfAsterisks. For cases like these, for loops are a life-saver (In more professional code (as professional as you can get with fancy terminal graphics) this would be done a bit differently, as in actuality using for-loops for such a thing makes the function O(N)).
The rest is up to you
Can modify the variables as you see fit. Key is to use a bunch of for loops and keep track of all the variables.
for (int i = 0; i < 8; i++) { //line number your on
for(int k = 0; k<i;k++)//keeps track of number of spaces to use, line number minus 1 spaces printed
{
System.out.print(" ");
}
for (int j = 8; j >i; j--) {//prints out 8 * and reduced by 1*line number
System.out.print("*");
}
System.out.println();//prints new line and initiates new line by i++
}

Java search a string for a substring UNLESS preceded by specific character

I'm attempting to write a Java program that searches for a specific substring (xyz) within a user-entered string, and keeping a running count, unless that substring is preceded by a period. At this point in the class, we've only used charAt and length, so if possible I need to stick to that. Additionally, we haven't used regular expressions at all, so that's out the window too.
I've managed to get the program working as desired, with one notable exception: if the String entered begins with a period, it fails to count any successive matches. This is what I've got so far:
System.out.println("Give me a String:");
String s1 = kb.nextLine();
int index = 0;
int count = 0;
while(index <= s1.length() - 1 && s1.charAt(index) != '.')
{
if(s1.charAt(index) == 'x' && s1.charAt(index + 2) == 'z')
{
count++;
}
index++;
}
System.out.println(count);
You can simply check the input string whether it starts with period. If so then you can use the following piece of code to handle the validation.
if(s1.charAt(0)!='.')
{
while(index <= s1.length() - 1 && s1.charAt(index) != '.')
{
if(s1.charAt(index) == 'x' && s1.charAt(index + 2) == 'z')
{
count++;
}
index++;
}
}
else
{
index=1;
while(index <= s1.length() - 1 && s1.charAt(index) != '.')
{
if(s1.charAt(index) == 'x' && s1.charAt(index + 2) == 'z')
{
count++;
}
index++;
}
}
System.out.println(count);
}
As this seems like a homework type of question I will attempt to guide you in the right direction first and provide a solution at a later time. I strongly encourage you to work through the problem on your own first to the best of your ability before you look at my solution (once I post it) and to read this page before going ANY further
First, consider the kinds of inputs you could receive. Since you didn't specify any limitations you could get things like:
"" (empty string)
"\n" (whitespace)
"x" (a single character)
"xx" (two characters string)
"abc" (string of correct length, but not containing your substring)
".xyz" (the substring to be ignored)
I could go on, but I'm sure you can come up with all the various combinations of weird things you might receive. These are just a few examples to get you started (along with those I posted in the comments already)
Next, think about what you need your algorithm to do. As I said in the comments it sounds like you want to count the occurrences of the substring "xyz" while ignoring the occurrences of the substring ".xyz". Now consider how you're going to look for these substrings - you're going to advance one character at a time from left to right across the String looking for a substring that matches one of these two possibilities. When you find one of them you'll either ignore it or count it.
Hopefully this helps and as I said, I will post a solution later after you've had some time to wrestle with the code. If you do solve it go ahead and post your solution (maybe edit your question to add the new code or add an answer) Finally I once again strongly urge you to read this page if you have not already.
EDIT #1:
I wanted to add a little more information and that is: you already have a pretty good idea of what you need to do in order to count your "xyz" substring at this point - despite the small flaw in the logic for inputs like "xaz", which is easily fixable. What you need to focus on is how to ignore the substring ".xyz" so think about how you could implement the ignore logic, what does it mean to ignore it? Once you answer that it should start coming together for you.
EDIT #2:
Below you will find my solution to the problem. Once again it's important to understand how the solution works not just copy and paste it. If you simply copy my code without understanding it you're cheating yourself out of the education that you're trying to gain. I don't have time at the moment to describe in detail why and how this code works, but I do plan to edit again later to add those details.
import java.util.Scanner;
public class Main {
private static Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Give me a String:");
String s1 = scan.nextLine();
System.out.println(countSubstrings(s1));
}
public static int countSubstrings(String s1){
int index = 0;
int count = 0;
while (index < s1.length()-2) {
if(s1.charAt(index) == '.' && s1.charAt(index+1) != '.'){
index++;
}
else if (index+2 < s1.length() && s1.charAt(index) == 'x' && s1.charAt(index + 1) == 'y'
&& s1.charAt(index + 2) == 'z') {
count++;
index+=2;
}
index++;
}
return count;
}
}
EDIT #3:
Here is the nuts and bolts of why the above code does what it does. First, we think about the fact that we're looking for 3 items (a triple) in a specific order within an array and if we see a fourth item (a period) immediately preceding the first item of the triple then we need to ignore the triple.
Per my previous edit we need to define what it means to ignore. In this case what we mean is to simply not count it and move on with our search for valid substrings to count. The simplest way to do that is to advance the index without incrementing the count.
So, ask yourself the following:
When should my loop stop? Since we're looking for triples we know we can stop if the length of the input String is less than 3 or when there are less than 3 characters left in the String that we have not examined yet. For example if the input is "xyzab" by the time we get to index 3 we know there's no possible way to form a triple where "a" is the first character in the triple and that therefore our counting is done.
Is there ever a time when I would not want to skip the next 3 characters after a period? After all the goal is to look for triples so wouldn't I want to skip 3 characters not just 1? Yes there is a time when you do NOT want to skip 3 characters and that's when you have something like ".axyz" because a valid triple could start as soon as the 2nd character past the period. So in fact you want to skip only 1 character.
This, and the fact that index is always incremented by 1 at the end of the loop (more on this later), is why the first condition inside the while only advances the index by 1:
if(s1.charAt(index) == '.' && s1.charAt(index+1) != '.'){
index++;
}
Is there ever a time when I would see a period and not wish to ignore (skip) the next character? Yes, when the next character is another period because it could indicate that another triple needs to be skipped. Consider the input "..xyz" which would result in a wrong answer if you encounter the first period and skip the second period since your algorithm could see the next three characters as a valid triple but in fact it is invalid because of the second period.
This is why the second half of the above condition exists:
`&& s1.charAt(index+1) != '.'`
Now ask yourself how to identify a valid triple. I'm sure by now you can see how to do this - check the current character, the next character, and the character after that for the values you want. This logic is the latter portion of the second if condition within the while:
s1.charAt(index) == 'x' && s1.charAt(index + 1) == 'y'
&& s1.charAt(index + 2) == 'z'
Whenever you're using calculations like index +1 or index +2 inside of a loop that is incrementing the index until it reaches a boundary you have to consider the possibility that your calculation will exceed the boundary because you can't rely on the loop to check this for you as the loop will not perform that check until either the end or beginning of the loop (depending on which kind of loop it is)
Considering the above you must ask yourself: How do I prevent out of boundary scenarios when I use these index+1, index+2, etc types of calculations? The answer is to add another piece to your condition:
index+2 < s1.length()
You may be wondering - why not add two checks since we're using index+1 and index+2? We only need one check to see if the greatest index we use will exceed the boundary in this case. If index +2 is beyond the bounds we don't care if index+1 is or is not because it won't matter we can't possibly have a matching substring.
Next, inside of the second if inside the while you see there is code to increment the index by 2: index+=2; This is done for efficiency since once we have identified a triple we know there is no way to form another triple with characters that are already part of another triple. Therefore we want to skip over them and just like the first bullet point we take advantage of the loop incrementing the index so we only need to increment by 2 and let the loop add the extra 1 later.
Finally we reach the end of the logic within the loop. This part you're already familiar with and that's the index++; which simply increments the position within the String that we're currently examining. Note that this works in tandem with the first bullet point. Take the example from the first bullet point of ".axyz". There is a period in index 0 and the character in index 1 is not another period so the logic from the first bullet point will increment index by 1, making it 1. At the end of the loop index is incremented again making it 2 thereby skipping over the period - at the start of the next loop index is 2, it was never 1 at the start of the loop.
Well, I hope this helps to explain how it all works and illustrate how to think about these sorts of problems. The basic principle is to visualize where your current element is and how you can use that to achieve your goal. At the same time think about what kinds of properties the different elements of your program have and how you can take advantage of them - such as the fact that once you identify a triple it is safe to skip over those characters because they have the property of only being usable once. As with any program you always want to try to create as many test inputs as you can to test all the weird boundary cases that might occur to ensure the correctness of your code. I realize you probably are not familiar with JUnit but it is a very useful tool and you might try researching the basics of using it when you have a little spare time, and the bonus is that if you use the Eclipse IDE it has integrated JUnit functionality you can use.

Coding Mastermind in Java

I was wondering how to code the game, Mastermind, in Java, but with things up a notch (I want to inform the user not only how many pegs they got right or wrong, but also how many they guessed correctly in the wrong slots).
For instance, say the RNG answer of 5 digits of numbers 1-6 is:
22354
... and the user's guess is:
32624
Resulting in:
two guessed correctly (2 and 4)
two guessed partially correct (2 and 3)
one guessed incorrectly (6).
Here's my code for informing the user what they got correct:
String answer = "22354";
String guess = "32624";
int correctPegs = 0;
for (int i = 0; i < 5; i++) {
char a = answer.charAt(i);
char g = guess.charAt(i);
if (a == g) {
correctPegs++;
}
}
System.out.println(correctPegs);
How would I find the partially correct ones?
... and for calculating how many the user guessed incorrectly, I was thinking of using basic algebra to find the remaining characters after finding the correct and partially correct ones.
I would put '0' into the strings where they match. Then for every char that is not a zero, I would look through the answer string again. If any character in the answer string matches, I would make them both zero, and increment outOfPlacePegs.
This guards against two corner cases I am assuming you do not want:
One is when you have '323' as the answer and '223' as the input. You don't want the first '2' to be recorded as out of place.
Second is when you have '223' as the answer and '442' as the input. You don't want this recorded as two numbers out of place.

Need help checking my logic please

I have this loop that won't stop when it should and it's only happen on my production server but not on my dev server. So I'm going crazy.
//objectName can be any value from [a-}],
char objectName = 'a'; //objectName is initialized with value 'a'
//before objectName hit the line below, it was increment objectName++; until the value of
//objectName = '}'
for( char c = objectName; c <= 'z'; c++ ){
//do something
}
objectName can be any character but in my case I know that my objectName will be "}" character, which is technically more than 'z'. So what I don't understand is why is my loop being executed still.
The funny thing is we have test server which uses JAVA 1.6.0_30, and we have try testing there and it's working just fine.
My Dev Server uses : java 1.6.0_45
My Prod Server uses : java 1.6.0_30
If you see anything wrong with my logic please let me know, any circumstance that will make my loop be active even when it shouldn't feel free to let me know.
I'm no expert so I could be wrong here but using characters to iterate through a for loop looks alien to me and probably not the best thing to be doing.
I would suggest using an array/(array)List of characters and iterating through the list that way or as #Chris said by getting the numeric value of the characters
for(int i = Character.getNumericValue(objectName); i <= Character.getNumericValue('z'); i++)
{
//System.out.println("test");
}
Like I said I'm no expert but using numbers to iterate through for loops seems like a better practice or at least a more stable one.
In your question you say "I have this loop that won't stop when it should..." when should it stop? Currently the loop is exiting when the condition turns false. Basically when 10 >= 35.
First off, how is '}' "technically" more than 'z'?
'}' is equivalent to -1 and 'z' is equivalent to positive 35.
Using the code that you haven't commented you will loop 26 times, as expected (using char 'a' & char 'z').
'a' is equivalent to 10 and 'z' is equivalent to 35.
You can check these values by using Character.getNumericValue()
char objectName = 'a';
for( char c = objectName; c <= 'z'; c++ ){
//System.out.println("test");
}
Yields the same result as:
for( int i = 10; i <= 35; i++ ){
//System.out.println("test");
}
Unless I have missed something, this seems like an overly complicated way to achieve a really simple result.
I would have asked for clarification on something but I can't comment.

Permutations, Recursion

I have an assignment: User enters a String, example ABCD and the program has to give out alll the permutations.
I don't want the whole code just a tip. this is what i got so far in thery i got nothing implemented.
Taking ABCD as an example:
get factorial of length of String in this case 4! = 24.
24/4 = 6 So first letter has to change after 6. so far so good.
than get factorial of remaining letters which are three 3! = 6.
6/3 =2 2 places for each letter. from here i don't know how it can continue to fill 24 places.
With this algorithm all i will have is
ABCD
ABD
AC
AC
AD
AD
B
B
B
B
B
B
.
. (continues with 6 C's and 6 D's)
I think my problem is i do not have alot of experience with recursive problems so who can suggest some programs to program to help me get to know recursion better please do.
Thanks! If somethings aren't clear please point out.
You are right that recursion is the way to go. The example you worked thru w/ the little bit of math was all correct, but kind of indirect.
Here's some pseudocode:
def permute(charSet, soFar):
if charSet is empty: print soFar //base case
for each element 'e' of charSet:
permute(charSet without e, soFar + e) //recurse
example of partial recursion tree
permute({A,B,C}, '')
/ | \
permute({B,C}, 'A') permute({A,C}, 'B') permute({A,B}, 'C')
/ \
permute({A}, 'BC') permute({C}, 'BA')
|
permute({}, 'BCA')<---BASE CASE, print 'BCA'
EDIT
To handle repeated characters without duplicating any permutations. Let unique be a function to remove any repeated elements from a collection (or string that is being treated like an ordered character collection thru indexing).
1) Store results (including dupes), filter them out afterwards
def permuteRec(charSet, soFar):
if charSet is empty: tempResults.add(soFar) //base case
for each element 'e' of charSet:
permute(charSet without e, soFar + e) //recurse
global tempResults[]
def permute(inString):
permuteRec(inString, '')
return unique(tempResults)
print permute(inString)
2) Avoid generating duplicates in the first place
def permute(charSet, soFar):
if charSet is empty: print soFar //base case
for each element 'e' of unique(charSet):
permute(charSet without e, soFar + e) //recurse
Make a method that takes a string.
Pick a letter out of the string and output it.
Create a new string with the input string minus the letter you picked.
call the above method with the new string if it has at least 1 character
do this picking of one letter for each possible letter.

Categories

Resources