public String reverse(String word) {
if ((word == null) || (word.length() <= 1)) {
return word;
}
return reverse(word.substring(1)) + word.charAt(0);
}
I have this code that professor sent me but I don't get it. I know what recursion is but I'm still a newbie at Java Programming so if anybody would care to explain to me the part
return reverse(word.substring(1)) + word.charAt(0);
what does the subString(1) does and the chartAt(0)?
This is recursion. Here are documentation for subString() and charAt().
Coming to how this works:
public static String reverse(String word) {
if ((word == null) || (word.length() <= 1)) {
return word;
}
return reverse(word.substring(1)) + word.charAt(0);
}
Pass1: reverse("user") : return reverse("ser")+'u';
Pass2: reverse("ser")+'u' : return reverse("er")+'s'+'u';
Pass3: reverse("er")+'s'+'u' : return reverse("r")+'e'+'s'+'u';
Pass4: reverse("r")+'e'+'s'+'u' : return 'r'+'e'+'s'+'u'; // because here "r".length()==1
The way the recursive part of this works is that to reverse a string, you remove the first character, reverse what's left, and then append the first character to the result. That's what the prof's code is doing.
word.substring(1) returns the substring starting at index 1 and going to the end
word.charAt(0) returns the character at index 0
There's a bit more going on when the two pieces are appended using +. The issue is that word.charAt(0) has a return type of char. Since the left-hand part of the + is a String, the Java language rules say that the right-hand side must be converted to a String if it isn't one. So the char value is first converted to a Character and then the toString() method of the Character class is called. This returns a String consisting of the single character.
It might have been more efficient code to write that line like:
return reverse(word.substring(1)) + word.substring(0, 1);
The two-argument version of substring returns the substring between the two indexes. That would eliminate the autoboxing and conversion to String.
return reverse(word.substring(1)) + word.charAt(0);
you should read it this way:
remove the first letter away from the word
reverse the rest (recursive call)
put the first letter at the end
if you assume this function reverses the strings of length N, you can easily see that it must reverse the strings of length N+1. If you realize that the word with at most one letter is the same if reversed (the first three lines of code), you have a complete very simple proof using Mathematical Induction that this function really reverses the string.
Related
Got something for you all.
As the title of the problem suggests, I am trying to implement a non-array, non-looping, recursive method to find the alphabetically last letter in a string.
I think that I understand the nature of the problem I'm trying to solve, but I don't know how to start with the base case and then the recursion.
Can anyone be willing to solve this problem?
In this case, I would like the following code:
//Method Definition
public static String findZenithLetter(String str) {
//Put actual working Java code that finds the alphabetically last letter of the desired string here.
//Use recursion, not loops! :)
//Don't use arrays! ;)
}
//Driver Code
System.out.println(findZenithLetter("I can reach the apex, at the top of the world."));
//Should print the String "x" if implemented properly
I have tried to attempt numerous, but currently failed ways of solving this problem, including but not limited to:
Sorting the string by alphabetical order then finding the last letter of the new string, excluding punctuation marks.
Using the compareTo() method to compare two letters of the string side by side, but that has yet to work as I am so tempted to use loops, not recursion. I need a recursive method to solve this, though. :)
In the end, the best piece of code that I've written for this problem was just a drawn-out way to compute just the last character of a string and not actually THE alphabetically last character.
This is quite simple. All you need is just iterate (in the recursion of course), and check all characters int he string with local maximum.
public static char findZenithLetter(String str) {
return findZenithLetter(str, 0, 'a');
}
private static char findZenithLetter(String str, int i, char maxCh) {
if (i >= str.length())
return maxCh;
char ch = Character.toLowerCase(str.charAt(i));
if (Character.isLetter(ch))
maxCh = ch > maxCh ? ch : maxCh;
return findZenithLetter(str, i + 1, maxCh);
}
Nibble off the first character at each recursion, returning the greater of it and the greatest found in the rest of the input:
public static String findZenithLetter(String str) {
if (str.isEmpty()) {
return ""; // what's returned if no letters found
}
String next = str.substring(0, 1);
String rest = findZenithLetter(str.substring(1));
return Character.isLetter(next.charAt(0)) && next.compareToIgnoreCase(rest) > 0 ? next : rest;
}
See live demo.
The check for Character.isLetter() prevents non-letter characters, which may be "greater than" letters being returned.
If no letters are found, a blank is returned.
I'm presently trying to understand a particular algorithm at the CodingBat platform.
Here's the problem presented by CodingBat:
*Suppose the string "yak" is unlucky. Given a string, return a version where all the "yak" are removed, but the "a" can be any char. The "yak" strings will not overlap.
Example outputs:
stringYak("yakpak") → "pak"
stringYak("pakyak") → "pak"
stringYak("yak123ya") → "123ya"*
Here's the official code solution:
public String stringYak(String str) {
String result = "";
for (int i=0; i<str.length(); i++) {
// Look for i starting a "yak" -- advance i in that case
if (i+2<str.length() && str.charAt(i)=='y' && str.charAt(i+2)=='k') {
i = i + 2;
} else { // Otherwise do the normal append
result = result + str.charAt(i);
}
}
return result;
}
I can't make sense of this line of code below. Following the logic, result would only return the character at the index, not the remaining string.
result = result + str.charAt(i);
To me it would make better sense if the code was presented like this below, where the substring function would return the letter of the index and the remaining string afterwards:
result = result + str.substring(i);
What am I missing? Any feedback from anyone would be greatly helpful and thank you for your valuable time.
String concatenation
In order to be on the same page, let's recap how string concatenation works.
When at least one of the operands in the expression with plus sign + is an instance of String, plus sign will be interpreted a string concatenation operator. And the result of the execution of the expression will be a new string created by appending the right operand (or its string representation) to the left operand (or its string representation).
String str = "allow";
char ch = 'h';
Object obj = new Object();
System.out.println(ch + str); // prints "hallow"
System.out.println("test " + obj); // prints "test java.lang.Object#16b98e56"
Explanation of the code-logic
That said, I guess you will agree that this statement concatenates a character at position i in the str to the resulting string and assigns the result of concatenation to the same variable result:
result = result + str.charAt(i);
The condition in the code provided by coding bat ensures whether the index i+2 is valid and then checks characters at indices i and i+2. If they are equal to y and k respectively. If that is not the case, the character will be appended to the resulting string. Athowise it will be discarded and the indexed gets incremented by 2 in order to skip the whole group of characters that constitute "yak" (with a which can be an arbitrary symbol).
So the resulting string is being constructed in the loop character by characters.
Flavors of substring()
Method substring() is overload, there are two flavors of it.
A version that expects two argument: the starting index inclusive, the ending index, exclusivesubstring(int, int).
And you can use it to achieve the same result:
// an equivalent of result = result + str.charAt(i);
result = result + str.substring(i, i + 1);
Another version of this method, that expects one argument will not be useful here. Because the result returned by str.substring(i) will be not a string containing a single character, but a substring staring from the given index, i.e. encompassing all the characters until the end of the string as documentation of substring(int) states:
public String substring(int beginIndex)
Returns a string that is a substring of this string. The substring
begins with the character at the specified index and extends to the
end of this string.
Examples:
"unhappy".substring(2) returns "happy"
"Harbison".substring(3) returns "bison"
"emptiness".substring(9) returns "" (an empty string)
Side note:
This coding-problem was introduced in order to master the basic knowledge of loops and string-operations. But actually the simplest to solve this problem is by using method replaceAll() that expects a regular expression and a replacement-string:
return str.repalaceAll("y.k", "");
For this Kata, i am given random function names in the PEP8 format and i am to convert them to camelCase.
(input)get_speed == (output)getSpeed ....
(input)set_distance == (output)setDistance
I have a understanding on one way of doing this written in pseudo-code:
loop through the word,
if the letter is an underscore
then delete the underscore
then get the next letter and change to a uppercase
endIf
endLoop
return the resultant word
But im unsure the best way of doing this, would it be more efficient to create a char array and loop through the element and then when it comes to finding an underscore delete that element and get the next index and change to uppercase.
Or would it be better to use recursion:
function camelCase takes a string
if the length of the string is 0,
then return the string
endIf
if the character is a underscore
then change to nothing,
then find next character and change to uppercase
return the string taking away the character
endIf
finally return the function taking the first character away
Any thoughts please, looking for a good efficient way of handing this problem. Thanks :)
I would go with this:
divide given String by underscore to array
from second word until end take first letter and convert it to uppercase
join to one word
This will work in O(n) (go through all names 3 time). For first case, use this function:
str.split("_");
for uppercase use this:
String newName = substring(0, 1).toUpperCase() + stre.substring(1);
But make sure you check size of the string first...
Edited - added implementation
It would look like this:
public String camelCase(String str) {
if (str == null ||str.trim().length() == 0) return str;
String[] split = str.split("_");
String newStr = split[0];
for (int i = 1; i < split.length; i++) {
newStr += split[i].substring(0, 1).toUpperCase() + split[i].substring(1);
}
return newStr;
}
for inputs:
"test"
"test_me"
"test_me_twice"
it returns:
"test"
"testMe"
"testMeTwice"
It would be simpler to iterate over the string instead of recursing.
String pep8 = "do_it_again";
StringBuilder camelCase = new StringBuilder();
for(int i = 0, l = pep8.length(); i < l; ++i) {
if(pep8.charAt(i) == '_' && (i + 1) < l) {
camelCase.append(Character.toUpperCase(pep8.charAt(++i)));
} else {
camelCase.append(pep8.charAt(i));
}
}
System.out.println(camelCase.toString()); // prints doItAgain
The question you pose is whether to use an iterative or a recursive approach. For this case I'd go for the recursive approach because it's straightforward, easy to understand doesn't require much resources (only one array, no new stackframe etc), though that doesn't really matter for this example.
Recursion is good for divide-and-conquer problems, but I don't see that fitting the case well, although it's possible.
An iterative implementation of the algorithm you described could look like the following:
StringBuilder buf = new StringBuilder(input);
for(int i = 0; i < buf.length(); i++){
if(buf.charAt(i) == '_'){
buf.deleteCharAt(i);
if(i != buf.length()){ //check fo EOL
buf.setCharAt(i, Character.toUpperCase(buf.charAt(i)));
}
}
}
return buf.toString();
The check for the EOL is not part of the given algorithm and could be ommitted, if the input string never ends with '_'
So the question goes like this:
Given a string and a second "word" string, we'll say that the word matches the string if it appears at the front of the string, except its first char does not need to match exactly. On a match, return the front of the string, or otherwise return the empty string. So, so with the string "hippo" the word "hi" returns "hi" and "xip" returns "hip". The word will be at least length 1. "
First off, I have no clue what the question is even asking. Second, I looked up a solution to it and I don't get the solution either. Can someone help me comprehend what is even happening? Is there an alternate way of doing this?
public String startWord(String str, String word) {
if (str.length() < 1) {
return "";
}
if (str.substring(1).indexOf(word.substring(1)) != 0) { // I am utterly confused here, wouldn't this always be true if it starts beyond zero?
return "";
}
return str.substring(0, word.length());
}
First off, I have no clue what the question is even asking.
You have a first string and a second string (word).
The word matches the first string if
The word matches the beginning of the first string.
The word matches the beginning of the first string even if the first letter of the word doesn't match the first letter of the front string.
If the word matches the first string, return the first word length characters of the first string. Otherwise, return an empty string.
The word will be at least length 1.
Second, I looked up a solution to it and I don't get the solution either. Can someone help me comprehend what is even happening?
Here's my solution to startWord. I hope it makes more sense.
public String startWord(String str, String word) {
String x = word.substring(1);
if (str.startsWith(x, 1)) {
return str.substring(0, word.length());
} else {
return "";
}
}
You're tasked with seeing if a string, str, starts with word. But you're not matching the first character. That's why you use "1" to specify you want only the string and word starting the second character. "0" would represent the first character. The "indexOf" method of a string searches for an instance of the word you pass in, and returns the index..the character number... where the match was found. So if it was found at the start..the first character... it'd return 0. Because you chopped off the first character of both using substring, you're just looking for a match at character 0.
If the index was not found at 0 (-1 for not found, or greater than 0 for word being found, but not in the beginning of str), then it's returning an empty string.
A slight alteration would be to chop off only the first character of "word" and see if it's found at index 1 of str. But it's simpler to chop off the first character of both and see if they line up at the start.
Another variation would be to do a "regex" pattern match, but that's going to be unnecessarily confusing for you.
Original str: "woogie"
Original word: "goog"
Is it a match?
Hack off the first character:
Shortened str: "oogie"
Shortened word: "oog"
"oog" is found to start at position 0 of "oogie", so indexOf returns 0.
public String startWord(String str, String word) {
int len1 = str.length();
int len2 = word.length();
String withoutFirst = word.substring(1,len2);
String result = "";
if(len1>=len2 && len2>0){
if(str.substring(0,len2).equals(word)){
result = word;
}else if(word.substring(1,len2).equals(str.substring(1,len2))){
result = str.substring(0,1) + word.substring(1,len2);
}
}else{
result = "";
}
return result;
}
I am trying to solve a codingbat problem using regular expressions whether it works on the website or not.
So far, I have the following code which does not add a * between the two consecutive equal characters. Instead, it just bulldozes over them and replaces them with a set string.
public String pairStar(String str) {
Pattern pattern = Pattern.compile("([a-z])\\1", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
if(matcher.find())
matcher.replaceAll(str);//this is where I don't know what to do
return str;
}
I want to know how I could keep using regex and replace the whole string. If needed, I think a recursive system could help.
This works:
while(str.matches(".*(.)\\1.*")) {
str = str.replaceAll("(.)\\1", "$1*$1");
}
return str;
Explanation of the regex:
The search regex (.)\\1:
(.) means "any character" (the .) and the brackets create a group - group 1 (the first left bracket)
\\1, which in regex is \1 (a java literal String must escape a backslash with another backslash) means "the first group" - this kind of term is called a "back reference"
So together (.)\1 means "any repeated character"
The replacement regex $1*$1:
The $1 term means "the content captured as group 1"
Recursive solution:
Technically, the solution called for on that site is a recursive solution, so here is recursive implementation:
public String pairStar(String str) {
if (!str.matches(".*(.)\\1.*")) return str;
return pairStar(str.replaceAll("(.)\\1", "$1*$1"));
}
FWIW, here's a non-recursive solution:
public String pairStar(String str) {
int len = str.length();
StringBuilder sb = new StringBuilder(len*2);
char last = '\0';
for (int i=0; i < len; ++i) {
char c = str.charAt(i);
if (c == last) sb.append('*');
sb.append(c);
last = c;
}
return sb.toString();
}
I dont know java, but I believe there is replace function for string in java or with regular expression. Your match string would be
([a-z])\\1
And the replace string would be
$1*$1
After some searching I think you are looking for this,
str.replaceAll("([a-z])\\1", "$1*$1").replaceAll("([a-z])\\1", "$1*$1");
This is my own solutions.
Recursive solution (which is probably more or less the solution that the problem is designed for)
public String pairStar(String str) {
if (str.length() <= 1) return str;
else return str.charAt(0) +
(str.charAt(0) == str.charAt(1) ? "*" : "") +
pairStar(str.substring(1));
}
If you want to complain about substring, then you can write a helper function pairStar(String str, int index) which does the actual recursion work.
Regex one-liner one-function-call solution
public String pairStar(String str) {
return str.replaceAll("(.)(?=\\1)", "$1*");
}
Both solution has the same spirit. They both check whether the current character is the same as the next character or not. If they are the same then insert a * between the 2 identical characters. Then we move on to check the next character. This is to produce the expected output a*a*a*a from input aaaa.
The normal regex solution of "(.)\\1" has a problem: it consumes 2 characters per match. As a result, we failed to compare whether the character after the 2nd character is the same character. The look-ahead is used to resolve this problem - it will do comparison with the next character without consuming it.
This is similar to the recursive solution, where we compare the next character str.charAt(0) == str.charAt(1), while calling the function recursively on the substring with only the current character removed pairStar(str.substring(1).