Coding Bat String challenge is failing tests - java

public int countYZ(String str) {
int count = 0;
for(int i = 0;i<str.length();i++)
if((str.charAt(i)=='y'||str.charAt(i)=='z')&&!(Character.isLetter(i+1)))
count++;
return count;
}
This code is failing the test for this criteria : Given a string, count the number of words ending in 'y' or 'z' -- so the 'y' in "heavy" and the 'z' in "fez" count, but not the 'y' in "yellow" (not case sensitive). We'll say that a y or z is at the end of a word if there is not an alphabetic letter immediately following it. (Note: Character.isLetter(char) tests if a char is an alphabetic letter.)
I tracked it by hand and cannot seem to figure out why it isn't working for many of the tests. For example, in "day fyyyz" it outputs 5 but it should be returning 2. Appreciate the help!

Two things to consider:
As pointed out by UnholySheep, Character.isLetter(i+1) isn't checking the i+1th character in the string. You'd need to use:
Character.isLetter(str.charAt(i+1))
But simply changing that can yield an IndexOutOfBoundsException, because you overrun the end of the string if the string ends with a y or z. So, change the second bit of the condition to
!(i+1 != str.length() && Character.isLetter(str.charAt(i+1)))
This also counts the y or z at the end of the string.
Of course, this can be written as:
i+1 == str.length() || !Character.isLetter(str.charAt(i+1))
which is a bit less awkward.
Overall condition:
if((str.charAt(i) == 'y' || str.charAt(i) == 'z')
&& (i+1 == str.length() || !Character.isLetter(str.charAt(i+1)))
If you want to make it case insensitive, use Character.toLowerCase(str.charAt(i)) before comparing to y and z.

Your function is return the total number of y and z characters in the string instead of the number of words ending in y or z. \\W is a regular expression token to target any non-word character in a string.
public int countYZ(String str) {
String[] words = str.split("\\W");
int tally = 0;
for (String w : words)
tally += (w.endsWith("y") || w.endsWith("z")) ? 1 : 0;
return tally;
}

This is a problem easy to solve with a regex:
String str = "day fyyyz provaz provy drad";
Matcher matcher = Pattern.compile("(?i)\\b\\w+[zy]\\b").matcher(str);
int i = 0;
while (matcher.find()) {
System.out.println(matcher.group());
i++;
}
System.out.println("found " + i);
This code will output:
day
fyyyz
provaz
provy
found 4
This regex (?i)\\b\\w+[zy]\\b means:
(?i) enable match case insensitive
\b match word boundary
\w+ match one or more word character (equal to [a-zA-Z0-9_])
[zy] Match a single character present in the list below [zy]
\b match word boundary
https://regex101.com/r/tLMobI/1

Related

How to validate a contiguous sequence of digits with regex?

I need to write a regex for PIN validation.
The PIN is 4-digits and must not consist of contiguous numbers.
Examples of contiguous numbers:
[ 1111, 1234, 9876, 8888, 0987, 0123 ]
I tried this link, but it only checks for identical digits, not contiguous ones.
Could you suggest working regex for me?
The regex only match
That is why a regex like (adjusted to 4 digits):
^(\\d)(?!\\1+$)\\d{3}$
, showed in link "this" (link found question) will only check for identical digits.
Note: The original expression is made a bit smaller, so it will be easier to follow - without the quantifiers. In expression '(?<!\1)\d', "\1 -> group(1)" matches “\d -> a didgit” that is not preceded by “group(1)”, using negative lookbehind. It doesn’t match an equal digit.
We would like to have arithmetic operators directly in the regex, applying it on "group(1)", in order to solve it with only regex, but that is not supported by regex.
Here is an alternative, not regex though, first the core code snippet:
int digit = Integer.parseInt(String.valueOf(pin.charAt(i)));
int nextDigit = Integer.parseInt(String.valueOf(pin.charAt(i + 1)));
if (digit >= nextDigit - 1 && digit <= nextDigit + 1) {
resultMap.put(pin, false);
break;
}
Code snippet in context and "testbench":
public static void main(String[] args) {
List<String> inputs =
Arrays.asList("1111", "1234", "9876"
, "8888", "0987", "0123"
, "1358", "0268", "9635");
Map<String, Boolean> resultMap = new LinkedHashMap<>();
for (String pin : inputs) {
for (int i = 0; i < pin.length() - 1; i++) {
resultMap.put(pin, true);
int digit = Integer.parseInt(String.valueOf(pin.charAt(i)));
int nextDigit = Integer.parseInt(String.valueOf(pin.charAt(i + 1)));
if (digit >= nextDigit - 1 && digit <= nextDigit + 1) {
resultMap.put(pin, false);
break;
}
}
}
System.out.println(resultMap);
}
Output:
{1111=false, 1234=false, 9876=false, 8888=false, 0987=false, 0123=false, 1358=true, 0268=true, 9635=true}

Special Palindrome from hackerrank

I am Solving a Hacker rank problem
https://www.hackerrank.com/challenges/special-palindrome-again/problem
I not able to pass test cases Still my logic is correct
I am able to find palindromes but my code finding an another palindrome which is not listed in explanation it leads to failure of test cases
List lstr=new ArrayList<>();
for(int i=0;i<s.length();i++)
{
for(int j=i+1;j<=s.length();j++)
{
String str=new StringBuilder(s.substring(i,
j)).reverse().toString();
if(s.substring(i, j).equals(str) && s.substring(i, j).length()>1 )
{
lstr.add(str);
}
}
return lstr.size()+s.length();
Input
5 asasd
special palindrome strings {a,s,a,s,d,asa,sas}
Input
7 abcbaba
special palindrome strings {a,b,c,b,a,b,a,bcb,bab,aba} but in above
example my program is finding abcba as palindrome also this leads to
failure of test cases
Special String Again
I gather you're not counting each possible special string.
Try this out, it passes all the cases.
static long substrCount(int n, String s) {
//automatically count each single character as a special string
//thus, the default number of special strings is equal to
//the length of the string
int numOfSpecialStrings = s.length();
//start iterating through the string
for (int i = 0; i < s.length(); i++) {
//to count all special strings, we
//we will restart the counting
//for each iteration.
int numOfRepeat = 0;
//this while loop takes care of the repetitive-character special strings
while (i + 1 < s.length() && s.charAt(i) == s.charAt(i + 1)) {
numOfRepeat++;
i++;
}
//In a repetitive-character string the total of all
//substrings can be calculated using the
//triangular numbers formula.
numOfSpecialStrings += (numOfRepeat * (numOfRepeat + 1) / 2);
//Now we have to take care of the special strings that
//are mirrored, but they can be e.g aba but can also
//be aabaa and etc. How do we take care of these if
//we can have an infinite amount of these?
//introduce a pointer that will take care of the substrings
//with minimum size 3 - it will check the i-1,i and i+1.
int pointer = 1;
//So, while we do not violate the boundary conditions of the loop
//we have increase the size of substring we are checking.
//E.g if pointer = 1 and we check
// aba, b is i, so i-pointer is a and i+pointer is a.
//We can see that a = a, so now we will expand our pointer
// and increment the numberOfSpecialStrings and
//will now reach i-2, i, i+2 and so on.
//This will go on until we either reach the end of the string, or the
//condition is not satisfied.
while (i - pointer >= 0 && i + pointer < s.length() &&
s.charAt(i + pointer) == s.charAt(i - 1)
&& s.charAt(i - pointer) == s.charAt(i - 1)) {
numOfSpecialStrings++;
pointer++;
}
}
System.out.println(numOfSpecialStrings);
return numOfSpecialStrings;
}

After Method: Cut String at '-' or ' '

The input string may contain hyphens and spaces that mark places to truncate the string. The output string will be a truncated version of the input string, and the input int value is the desired length of the output string. The output string should truncate the input string at the first legal spot so the output string will have the desired length. If the truncation happens at a space, the output does not include the space, but if the truncation happens at a hyphen, the output includes the hyphen. No other hyphens are included in the output, but the other spaces are.
How can I fix my code to get the "What code should output" output without using arrays and breaks?
public static String after(int length, String s1) {
StringBuilder sb = new StringBuilder();
int x = 0;
for(; sb.length() < length && x < s1.length() - 1; x = x + 1) {
if(s1.charAt(x) != '-') {
sb.append(s1.charAt(x));
}
}
for(; x < sb.length() && s1.charAt(x) - 1 != '-'; x = x + 1) {
sb.append(s1.charAt(x));
}
if(s1.charAt(x) == ' ' && s1.length() + 1 == s1.length()) {
sb.append(s1.charAt(x));
}
return sb.toString();
}
Input are:
HW2.after(5, "La-te-ly the-re.")
HW2.after(6, "La-te-ly the-re.")
HW2.after(7, "La-te-ly the-re.")
I am getting the output :
"Latel"
"Lately"
"Lately "
What Actually output is:
"Late-"
"Lately"
"Lately the-"
Sounds like a homework question, so I'll just give you the approach I used, so you can think through the coding for yourself...
Stop your first loop one short of the number of requested characters. You have to not skip spaces, but keep a count of them, and subtract that from sb.length() you're testing in your loop because your desired length excludes spaces.
Then deal with the case where you're now pointing to a space, by testing for that, and if true, adding it to the output string and advancing x.
Then keep looking at the next character and adding it to the result as long as it isn't a dash or a space.
Finally, if you stopped on a dash, add it to the output.

(Java ) problems with myString.charAt(i) > "1" or myString.charAt(i) < "A"

I have a car Object which is supposed to have a characteristic. The characteristic is supposed to have the requirements: starts with two capital letter followed by a number from 1-9 followed by 4 numbers from 0-9.
public void writeCharacteristic(){
System.out.println("write down the characteristic for the car.");
String characteristic = kb.nextLine();
progress = false;
if (characteristic.length() != 7){
System.out.println("The string is not 7 letter/numbers long");
progress = false;
}
for(int i = 0; i < 2; ++i){
if (characteristic.charAt(i) < "A" || characteristic.charAt(i) > "Z"){
System.out.println(" character number " + i + " is invalid");
progress = false;
}
}
if (characteristic.charAt(3) < "1" || characteristic.charAt(3) > "9")
progress = false;
for (int j = 3; j < 7; ++j){
if (characteristic.charAt(j) < 0 || characteristic.charAt(j) > 9)
progress =false;
}
if (progress == false){
System.out.println("characteristic will have the value null.");
characteristic = null;
}
if (progress == true)
car.setCharacteristic(characteristic);
}
I'm having a problem at the lines "if (characteristic.charAt(i) < "A" || characteristic.charAt(i) > "Z"){"
The compiler is saying "The operator < is undefined for the argument type(s) char, String"
Any help is highly appreciated, thanks.
In Java, you can compare a character (char) to a character, but you can't compare a character to a String. charAt returns a character, so you must compare its result to a character.
These are String
"A" "Z" "1" "9"
And these are characters
'A' 'Z' '1' '9'
You can compare a character to an integer (int), but the result may not be what you want. So in the code below:
for (int j = 3; j < 7; ++j){
if (characteristic.charAt(j) < 0 || characteristic.charAt(j) > 9)
0 and 9 should be change to '0' and '9'.
Note: There is another unrelated logic error in your code:
String characteristic = kb.nextLine();
progress = false;
Shouldn't progress be set to true here?
I would certainly check out the other answers on this page re. character comparisons. However, I would perhaps suggest a different approach given:
starts with two capital letter followed by a number from 1-9 followed
by 4 numbers from 0-9
and investigate regular expressions. Something like:
[A-Z]{2}[1-9][0-9]{4}
would satisfy the above requirement.
Use single quotes for chars, double quotes for Strings.
characteristic.charAt(3) < '1'
there is meaning for single and double quotes in java
And for your situation best suits is a regex
Replace the double quotes with single quotes.
You'll also have to put single quotes around the numbers when comparing them with chars, even though the compiler doesn't complain.
Compare like this
characteristic.charAt(3) < '1'
First, you can achieve this goal with regexp:
[A-Z]{2}[1-9][0-9]{4}
(Read Pattern article to know how to use it).
If you want to do it as you started - use singleqoutes instead of doublequotes with characters. e.g. "a" -> 'a'.
If you want to assign value to char use single quote. If it is a String use double quote
char myChar='a';
String myString="a";
so
characteristic.charAt(3) < "1" should change as characteristic.charAt(3) < '1'

Display the number of the characters in a string

I have a Java question: I am writing a program to read a string and display the number of characters in that string. I found some example code but I don't quite understand the last part - can anyone help?
int[] count = countLetters(line.toLowerCase());
for (int i=0; i<count.length; i++)
{
if ((i + 1) % 10 == 0)
System.out.println( (char) ('a' + i)+ " " + count[i]);
else
System.out.print( (char) ('a' + i)+ " " + count[i]+ " ");
}
public static int[] countLetters(String line)
{
int[] count = new int[26];
for (int i = 0; i<line.length(); i++)
{
if (Character.isLetter(line.charAt(i)))
count[(int)(line.charAt(i) - 'a')]++;
}
return count;
}
Your last loop is :
For every character we test if it's a letter, if yes, we increment the counter relative to that character. Which means, 'a' is 0, 'b' is 1 ... (in other words, 'a' is 'a'-'a' which is 0, 'b' is 'b'-'a' which is 1 ...).
This is a common way to count the number of occurrences of characters in a string.
The code you posted counts not the length of the string, but the number of occurrences of alphabet letters that occur in the lowercased string.
Character.isLetter(line.charAt(i))
retrieved the character at position i and returns true if it is a letter.
count[(int)(line.charAt(i) - 'a')]++;
increments the count at index character - 'a', this is 0 to 26.
The result of the function is an array of 26 integers containing the counts per letter.
The for loop over the counts array ends the printed output every 10th count and uses
(char) ('a' + i)
to print the letter that the counts belongs to.
I guess you are counting the occurences of letters, not characters ('5' is also a character).
The last part:
for (int i = 0; i<line.length(); i++)
{
if (Character.isLetter(line.charAt(i)))
count[(int)(line.charAt(i) - 'a')]++;
}
It iterates over the input line and checks for each character if it is a letter. If it is, it increments the count for that letter. The count is kept in an array of 26 integers (for the 26 letters in the latin alphabet). The count for letter 'a' is kept at index 0, letter 'b' at 1, 'z' at 25. To get the index the code subtracts the value 'a' from the letter value (each character not only is a character/glyph, but also a numeric value). So if the letter is 'a' it subtracts the value of 'a' which should be 0 and so on.
In the method countLetters, the for loop goes through all characters in the line. The if checks to make sure it's a letter, otherwise it will be ignored.
line.charAt() yields the single character at position i. The type of this is char.
Now deep inside Java, a char is just a number corresponding to a character code. Lowercase 'a' has a character code of 97, 'b' is 98 and so on. (int) forces conversion from char to int. So we take the character code, let's say it's a 'b' so the code is 98, and we subtract the code for 'a', which is 97, so we get the offset 1 (from the beginning of the alphabet). For any letter in the alphabet, the offset will be between 0 and 25 (inclusive).
So we use that offset as an index into the array count and use ++ to increment it. Then later the loop in the top part of the program can print out the counts.
The loop at the top is using the reverse "trick" to convert those offsets from 0 to 25 back into letters from a to z.
The 'last part', the implementation of the loop is really hard to understand. Close to obfuscation ;) Here's a refactoring of the count method (split in two method, a general one for all chars and a special on for just the small capital letters:
public static int[] countAllASCII(String line) {
int[] count = new int[256];
char[] chars = line.toCharArray();
for (char c : chars) {
int index = (int) c;
if (index < 256) {
count[index]++;
}
}
return count;
}
public static int[] countLetters(String line) {
int[] countAll = countAll(line);
int[] result = new int[26];
System.arraycopy(countAll, (int) 'a', result, 0, 26);
return result;
}
General idea: the countAll method just counts all chars. Yes, the array is bigger, but in these dimensions, nobody cares today. The advantage: I don't have to test each char. The second method just copy the area of interest into a new (resulting) array and returns it.
EDIT
I'd changed my code for a less unfriendly comment as well. Thanks anyway, Bombe.

Categories