For further help with Coding Bat (Java), please check out my books. I am also available for tutoring.
When I began working on the String-3 section of CodingBat, I felt mislead by the description, which said “Harder String problems — 2 loops.” However, most problems can be solved by only using one loop. The difficulty of the exercises is quite uneven, so don’t get frustrated if some take considerably more time than others.
All solutions were successfully tested on 23 February 2013.
countYZ:
public int countYZ(String str) { int count = 0; str = str.toLowerCase() + " "; for (int i = 0; i < str.length() - 1; i++) if ((str.charAt(i) == 'y' || str.charAt(i) == 'z') && !Character.isLetter(str.charAt(i + 1))) count++; return count; }
The string manipulation in line 3 takes care of the edge case where the last letter in the string is checked. In my opinion, this is cleaner than adding an extra condition in the for loop.
withoutString:
public String withoutString(String base, String remove) { String result = ""; int index = base.toLowerCase().indexOf(remove.toLowerCase()); while (index != -1) { result += base.substring(0, index); base = base.substring(index + remove.length()); index = base.toLowerCase().indexOf(remove.toLowerCase()); } result += base; return result; }
equalIsNot:
public boolean equalIsNot(String str) { int countIs = 0; int countNot = 0; str = str + "X"; for (int i = 0; i < str.length() - 2; i++) { if (str.substring(i, i + 2).equals("is")) countIs++; if (str.substring(i, i + 3).equals("not")) countNot++; } return (countIs == countNot); }
The string manipulation in line 4 avoids a second for loop. By lengthening the string by a character that is not in “is” or “not”, it’s possible to do all necessary checks in just one pass.
gHappy:
public boolean gHappy(String str) { str = "X" + str + "X"; // for corner cases for (int i = 1; i < str.length() - 1; i++) if (str.charAt(i) == 'g' && str.charAt(i - 1) != 'g' && str.charAt(i + 1) != 'g') return false; return true; }
countTriple:
public int countTriple(String str) { int count = 0; for (int i = 0; i < str.length() - 2; i++) if (str.charAt(i) == str.charAt(i + 1) && str.charAt(i + 1) == str.charAt(i + 2)) count++; return count; }
sumDigits:
public int sumDigits(String str) { int sum = 0; for (int i = 0; i < str.length(); i++) if (Character.isDigit(str.charAt(i))) sum += Integer.parseInt(str.substring(i, i + 1)); return sum; }
For further help with Coding Bat (Java), please check out my books. I am also available for tutoring.
For the withoutString problem, I think that using the index method is against the spirit of exercise. My solution is a lot longer, but it forced to think more deeply about the problem.
public String withoutString(String base, String remove) {
int len=remove.length();
String result=””;
for (int i=0;i<len;i++){
base+=" ";
}
String remove1=remove.toLowerCase();
String remove2=remove.toUpperCase();
for (int i=0;i<base.length()-len;i++){
if (base.substring(i,i+len).equals(remove) ||
base.substring(i,i+len).equals(remove1) ||
base.substring(i,i+len).equals(remove2)){
i+=len-1;
}
else{
result+=base.charAt(i);
}
}
return result;
}
Nick Parlante explicitly mentions the indexOf method in this article:
http://codingbat.com/doc/java-string-indexof-parsing.html
Further, I highly doubt that there is any deep insight to be gained from writing a loop. This is a purely mechanical procedure that is abstracted away in more expressive languages.
A much shorter solution to withoutString-method would be to use the replaceAll-method that takes a regular expresion as argument, and then use (?i) to make it case-insensitive matching. :
public String withoutString(String base, String remove) {
return base.replaceAll(“(?i)”+remove,””);
}
By using inbuilt methods like the one you mentioned you defeat the purpose of the Coding Bat exercises.
But you use three built-in methods of the string-class yourself. I don’t see the big difference.
I use a rather narrow subset of inbuilt methods, namely those that are mentioned by Nick Parlante in either the supplementary articles on his site, or in the commentary of the exercises. Indeed, there is a mountain of difference between using, for instance, charAt() and replaceAll(). Maybe spend a moment or two reflecting on how those methods may be implemented. This might lead to an important realization.
This is my code for WithoutString:
public String withoutString(String base, String remove) {
int len = remove.length();
remove = remove.toLowerCase();
for(int i = 0; i len-1) i -= len+1;
}
}
if(base.equals(remove))return “”;
return base;
}
Dear Sir,
The solution given for sumDigits caters to the sum of all digits in the String. The question however expects to return the sum of numbers separated by digits other than numbers.
Eg. aa11b33 in your solution returns 8 but it should return 44.
Pls advice
You are mistaken. The corresponding CodingBat page (http://codingbat.com/prob/p197890) explicitly mentions this example:
sumDigits(“aa11b33”) → 8
WIth a little help from your example, I did equalsIsNot in a bit more future-proof way:
public boolean equalIsNot(String str) {
str = str + "x"; // Easier to check until last character
return appearances("is", str) == appearances("not", str);
}
public int appearances(String needle, String hay) {
int count = 0;
for(int i=0; i<hay.length() - needle.length(); i++) {
if(hay.substring(i, i+needle.length()).equals(needle)) {
count++;
}
}
return count;
}
for countYZ, why is there a ” “/(a space) after str.toLowerCase()? I got everything else and turns out if I don’t have the space it’s off by one in a lot of situations.
nevermind, I got it. You need the space so you can check the last character. Originally I had this:
str= str.toLowerCase();
int counter=0;
for(int i=0; i<str.length()-1;i++)
{
if(str.charAt(i)=='y'&& Character.isLetter(str.charAt(i+1))==false ||str.charAt(i)=='z' && Character.isLetter(str.charAt(i+1))==false )
counter++;
}
if(str.charAt(str.length()-1)== 'y' || str.charAt(str.length()-1)== 'z' )
counter++;
return counter;
yours is a much more efficient version. BTW, thanks for all your work!
really like the equalsIsNot solution!
wouldn’t have thought to use the original string length minus the shorter value to limit the loop, but then search a longer temporary string.
thanks!
This is a shorter solution to withoutString, and it doesn’t require storage of a new variable ‘res’.
public String withoutString(String base, String remove) {
int index = 0;
while(index!=-1){
index = base.toLowerCase().indexOf(remove.toLowerCase());
if (index!=-1){
base = base.substring(0,index)+base.substring(index+remove.length());
}
}
return base;
}
Someone unfamiliar with what this function is supposed to achieve will likely immediately question why you check for the same condition in two places. Indeed, you can solve withoutString() without a nested if-statement. In my solution, I can of course trivially merge lines 9 and 10, which makes my solution as short as yours, and with a simpler execution path. So, much ado about nothing.
My solution
public int countYZ(String str) {
int count=0;
str=str.toLowerCase();
str=str.replaceAll(“[0-9]”, “!”);
String[] arr = str.split(“[^\\w]”);
for (int i = 0; i < arr.length; i++)
if(arr[i].endsWith("y") || arr[i].endsWith("z")) count++;
return count;
}