Monthly Archives: February 2013

CodingBat: Java. String-3, Part II

sameEnds:

public String sameEnds(String string) {
	String result = "";
	int len = string.length();
	for (int i = 0; i <= len / 2; i++)
		for (int j = len / 2; j < len; j++)
			if (string.substring(0, i).equals(string.substring(j)))
				result = string.substring(0, i);
	return result;
}

The variable in line 3 makes the code a bit more compact.

mirrorEnds:

public String mirrorEnds(String string) {
	String result = "";
	int len = string.length();
	for (int i = 0, j = len - 1; i < len; i++, j--)
		if (string.charAt(i) == string.charAt(j))
			result += string.charAt(i);
		else break;
	return result;
}

maxBlock:

public int maxBlock(String str) {
	int max = 0;
	for (int i = 0; i < str.length(); i++) {
		int count = 0;
		for (int j = i; j < str.length(); j++) {
			if (str.charAt(i) == str.charAt(j)) count++;
			else break;
		}
		if (count > max) max = count;
	}
	return max;
}

sumNumbers:

public int sumNumbers(String str) {
		int sum = 0;
		for (int i = 0; i < str.length(); i++) {
			if (Character.isDigit(str.charAt(i))) {
				int count = 0;
				for (int j = i; j < str.length(); j++) {
					if (Character.isDigit(str.charAt(j))) count++;
					else break;
				}
				sum += Integer.parseInt(str.substring(i, i + count));
				i += count;
			}
		}
		return sum;
}

notReplace:

public String notReplace(String str) {
	String result = "";
	str = " " + str + "  "; // avoid issues with corner cases
	for (int i = 0; i < str.length() - 2; i++) {
		if (str.charAt(i) == 'i') {
			if (str.charAt(i + 1) == 's'
					&& !Character.isLetter(str.charAt(i + 2))
					&& !Character.isLetter(str.charAt(i - 1))) {
				result += "is not";
				i += 1;
			} else result += "i";
		} else result += str.charAt(i);
	}
	return result.substring(1);
}

CodingBat: Java. String-3, Part I

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;
}

CodingBat: Java. String-2, Part II

repeatFront:

public String repeatFront(String str, int n) {
	String res = "";
	for (int i = n; i > 0; i--)
		res += str.substring(0, i);
	return res;
}

repeatSeparator:

public String repeatSeparator(String word, String sep, int count) {
	String res = "";
	if (count == 0) return "";
	while (count > 1) {
		res += word + sep;
		count--;
	}
	return res + word;
}

prefixAgain:

public boolean prefixAgain(String str, int n) {
	String prefix = str.substring(0, n);
	for (int i = n; i <= str.length() - prefix.length(); i++)
		if (str.substring(i, i + prefix.length()).equals(prefix))
			return true;
	return false;
}

xyzMiddle:

public boolean xyzMiddle(String str) {
	int len = str.length();
	if (len < 3) return false;
	if (len % 2 == 1)
		return str.substring(len/2 - 1, len/2 + 2).equals("xyz");
	return str.substring(len/2 - 2, len/2 + 1).equals("xyz") 
			|| str.substring(len/2 - 1, len/2 + 2).equals("xyz");
}  

getSandwich:

public String getSandwich(String str) {  
	int first = str.indexOf("bread");
	int last = str.lastIndexOf("bread");
	if (first == last) return "";
	return str.substring(first+5, last);
}

sameStarChar:

public boolean sameStarChar(String str) {  
	for (int i = 1; i < str.length()-1; i++)
		if (str.charAt(i) == '*' && str.charAt(i-1) != str.charAt(i+1))
			return false;
	return true;
}

zipZap:

public String zipZap(String str) {
	for (int i = 0; i < str.length()-2; i++)
		if (str.charAt(i) == 'z' && str.charAt(i+2) == 'p')
			str = str.substring(0,i+1) + str.substring(i+2);
	return str;
}

starOut:

public String starOut(String str) {	
	while (str.indexOf('*') != -1) {
		if (str.equals("*")) return "";
		int starPos = str.indexOf('*');
		int secondStar = str.indexOf('*', starPos+1);
		if (secondStar - starPos == 1) {
			str = str.substring(0,starPos) + str.substring(secondStar);
			continue;
		}
		if (starPos == 0) str = str.substring(starPos+2);
		else if (starPos == str.length()-1)
			str = str.substring(0, str.length()-2);
		else str = str.substring(0, starPos-1) + str.substring(starPos+2);
	}
	return str;
}

plusOut:

public String plusOut(String str, String word) {
	int start = 0;
	int end = str.indexOf(word);
	while (end != -1) {
		for (int i = start; i < end; i++)
			str = str.substring(0,i) + "+" + str.substring(i+1);
		start = end + word.length();
		end = str.indexOf(word, start);
	}
	for (int i = start; i < str.length(); i++)
		str = str.substring(0,i) + "+" + str.substring(i+1);
	return str;
}

wordEnds:

public String wordEnds(String str, String word) {
	String res = "";
	int pos = str.indexOf(word);
	while (pos != -1) {
		if (pos != 0) res += str.charAt(pos-1);
		if (pos + word.length() == str.length()) break; 
		res += str.charAt(pos + word.length());
		pos = str.indexOf(word, pos+1);
	}
	return res; 
}

CodingBat: Java. String-2, Part I

For the problems in the String-2 section of CodingBat, as well as all subsequent sections, it’s often a good idea to sketch the solution before starting to program. Some of the exercises are moderately complex, given the scope of the website, which means that you could easily find yourself going down the wrong path if you just rushed in. Of course this only applies if you restrict yourself to the basic set of Java methods mentioned on CodingBat. A few of the exercises pose little challenge if you use inbuilt functions of Java that go beyond the subset that is covered by CodingBat, but doing so would completely defeat the purpose of doing the exercises. After all, the point is not to merely pass the test cases, but to practice algorithmic thinking.

All solutions were successfully tested on 17 February 2013.

doubleChar:

public String doubleChar(String str) {
	String result = "";
	for (int i = 0; i < str.length(); i++) {
		char add = str.charAt(i);
		result += "" + add + add;
	}
	return result;
}

The concatenation with the empty string is necessary to avoid converting the characters into ASCII codes. It’s shorter than extracting a substring of length 1. If the empty string looks too esoteric for you, then feel free to rewrite that line as “result = result + add + add;”.

countHi:

public int countHi(String str) {
	int count = 0;
	for (int i = 0; i < str.length()-1; i++)
		if (str.substring(i, i+2).equals("hi"))
			count += 1; 
	return count;
}

catDog:

public boolean catDog(String str) {
	int cats = 0;
	int dogs = 0;
	for (int i = 0; i < str.length()-2; i++) {
		if (str.substring(i, i+3).equals("cat"))
			cats += 1;
		if (str.substring(i, i+3).equals("dog"))
			dogs += 1;
	}
	return cats == dogs;
}

countCode:

public int countCode(String str) {
	int count = 0;
	for (int i = 0; i < str.length()-3; i++)
		if (str.charAt(i) == 'c' && str.charAt(i+1) == 'o' 
		&& str.charAt(i+3) == 'e')
			count++;
	return count;
}

endOther:

public boolean endOther(String a, String b) {
	a = a.toLowerCase();
	b = b.toLowerCase();
	boolean test1 = a.length() >= b.length() 
			&& a.substring(a.length() - b.length()).equals(b);
	boolean test2 = b.length() >= a.length() 
			&& b.substring(b.length() - a.length()).equals(a);
	return test1 || test2;
}

Please note that you are not supposed to use endsWith(). Therefore, if you come up with the following solution, you’ve missed the point:

public boolean endOther(String a, String b) {
	a = a.toLowerCase();
	b = b.toLowerCase();
	return a.endsWith(b) || b.endsWith(a);  
}

xyzThere:

public boolean xyzThere(String str) {
	if (str.length() >= 3) {
		if (str.substring(0,3).equals("xyz")) return true;
		for (int i = 0; i < str.length()-3; i++)
			if (str.substring(i+1, i+4).equals("xyz") && 
					str.charAt(i) != '.')
				return true;
	}
	return false;
}

bobThere:

public boolean bobThere(String str) { 
	if (str.length() >= 3)
		for (int i = 0; i < str.length() - 2; i++)  
			if (str.charAt(i) == 'b' && str.charAt(i+2) == 'b')
				return true;
	return false;
}

xyBalance:

public boolean xyBalance(String str) {
	int lastX = str.lastIndexOf("y");
	int lastY = str.lastIndexOf("x");
	if (lastX == -1 && lastY == -1) return true;
	return (lastX > lastY);
}

The method lastIndexOf() is mentioned in the CodingBat tutorials.

mixString:

public String mixString(String a, String b) {
	String res = "";
	for (int i = 0; i < Math.min(a.length(), b.length()); i++)
		res += "" + a.charAt(i) + b.charAt(i);
	if (a.length() > b.length())
		return res + a.substring(b.length());
	return res + b.substring(a.length());
}

repeatEnd:

public String repeatEnd(String str, int n) {
	String res = "";
	for (int i = 0; i < n; i++)
		res += str.substring(str.length()-n);
	return res;
}

CodingBat: Java. Logic-2

The Logic-2 section of CodingBat contains just nine exercises. Yet, there are slightly more challenging than any of the pervious exercises, which means that you may have to spend more time on them, compared to, say, String-1. “makeBricks” is a favorite of mine, not just because some of the solutions floating around on the Internet are nothing but comical. It’s a similar story with “makeChocolate”.

All solutions were successfully tested on 10 February 2013.

makeBricks:

public boolean makeBricks(int small, int big, int goal) {
	return goal - big * 5 <= small
			&& goal % 5 <= small;
}

I split the line to make the expression more readable.

loneSum:

public int loneSum(int a, int b, int c) {
	if (a == b && b == c) return 0;
	if (a == b) return c;
	if (a == c) return b;
	if (b == c) return a;
	return a + b + c;
}

luckySum:

public int luckySum(int a, int b, int c) {
	if (a == 13) return 0;
	if (b == 13) return a;
	if (c == 13) return a + b;
	return a + b + c;
}

noTeenSum:

public int noTeenSum(int a, int b, int c) {
	return fixTeen(a) + fixTeen(b) + fixTeen(c);
}

public int fixTeen(int n) {
	return (n >= 13 && n < 15 || n > 16 && n <= 19) ? 0 : n;
}

roundSum:

public int roundSum(int a, int b, int c) {
	return round10(a) + round10(b) + round10(c);
}

public int round10(int num) {
	return (num % 10 < 5) ? (num / 10 * 10) : (num / 10 * 10 + 10);
}

closeFar:

public boolean closeFar(int a, int b, int c) {
	if (Math.abs(b - c) < 2) return false;
	return Math.abs(a - b) <= 1 && Math.abs(a - c) >= 2
			|| Math.abs(a - c) <= 1 && Math.abs(a - b) >= 2;
}

blackjack:

public int blackjack(int a, int b) {
	if (a > 21 && b > 21) return 0;
	if (a > 21 && b <= 21) return b;
	if (a <= 21 && b > 21) return a;
	return Math.max(a, b);
}

evenlySpaced:

public boolean evenlySpaced(int a, int b, int c) {
	int min = Math.min(Math.min(a, b), c);
	int mid = Math.max(Math.min(a, b), c);
	int mid2 = Math.min(Math.max(a, b), c);
	int max = Math.max(Math.max(a, b), c);
	return Math.abs(mid - min) == Math.abs(mid - max)
			|| Math.abs(mid2 - min) == Math.abs(mid2 - max); 
}

makeChocolate:

public int makeChocolate(int small, int big, int goal) {
	int maxBig = goal / 5;
	if (big > maxBig)
		return (goal <= 5 * maxBig + small) ? (goal - 5 * maxBig) : -1;
	return (goal <= 5 * big + small) ? (goal - 5 * big) : -1;
}

The parentheses in the return statements are not necessary, but they allow you to parse the statements more quickly since you can immediately identify all parts of the ternary operator.