I'm trying to teach myself Java and I've recently been doing online practice problems with a built in compiler. My code is working great for most of the conditions except for two in which the string length is less than two.
The URL to this specific practice problem is: http://codingbat.com/prob/p123384
Problem:
Given a string, return a new string where the first and last chars have been exchanged.
Example
frontBack("code") should be→ "eodc"
frontBack("a") should be→ "a"
frontBack("ab") should be→ "ba"
Here's my code:
public String frontBack(String str) {
char firstChar = str.charAt (0);
char lastChar = str.charAt (str.length()-1);
String middle = str.substring(1, str.length()-1);
if (str.length()>=3){
return lastChar + middle + firstChar;
}
else {
return new StringBuilder(str).reverse().toString();
}
}
These are the two conditions that error
frontBack("a") should be→ "a"
"Exception:java.lang.StringIndexOutOfBoundsException: String index out of range: -1 (line number:4)"
frontBack("") should be→ ""
"Exception:java.lang.StringIndexOutOfBoundsException: String index out of range: 0 (line number:2)"
Here's the solution, the code that works
public String frontBack(String str) {
if (str.length() <= 1) return str;
String mid = str.substring(1, str.length()-1);
// last + mid + first
return str.charAt(str.length()-1) + mid + str.charAt(0);
}
What's the difference between my code and the solution?
Any help would be great. I'm confused on this one since my else statement simply returns the original string. Why would any of the variables (frontChar, middle, lastChar) affect the original string I'm returning? Thanks in advance!
First I want to say thank you to everyone that helped me!*
I've reworked my code and narrowed it down to one simple difference. That difference is the placement of an explicit statement to account for strings equal to or less than one. This apparently can't be handled implicitly by a catch-all else statement. Still not exactly sure why? Here is the same code with one minor difference; Explicit vs Implicit
This code works... Explicitly return str if string length is less than or equal to 1.
public String frontBack(String str) {
// This line below is the only difference
if (str.length() <= 1) {
return str;
}
char firstChar = str.charAt (0);
char lastChar = str.charAt (str.length()-1);
String middle = str.substring(1, str.length()-1);
if (str.length()>=2){
return lastChar + middle + firstChar;
}
else {
return str;
}
}
This code doesn't work... Implicitly return str with an else statement if string length is less than or equal to 1.
public String frontBack(String str) {
char firstChar = str.charAt (0);
char lastChar = str.charAt (str.length()-1);
String middle = str.substring(1, str.length()-1);
if (str.length()>=2){
return lastChar + middle + firstChar;
}
else {
return str;
}
}
You need to program to defend
1.
for one character String
String middle = str.substring(1, str.length()-1);
this would be
str.substring(1, 0)
which is invalid
2.
for empty string (length = 0 ) your code will attempt to look at index = -1 which is invalid, or even index = 0 is invalid
3.
what if str is null
You always have to think of boundary conditions:
str is null? str is empty("") str is 1 char?
also bear in mind that Java's substring is inclusive on start position but exclusive on the end.
public String frontBack(String str) {
if (str == null || str.length()<2){
//if str is null - return empty. else return the string itself
return str == null ? "" : str;
}else{
//do the actual first last swap
return str.charAt(str.length()-1)+ str.substring(1,str.length()-1) + str.charAt(0);
}
}
I've reworked my code and narrowed it down to one simple difference. That difference is the placement of an explicit statement to account for strings equal to or less than one. This apparently can't be handled implicitly by a catch-all else statement. Still not exactly sure why?
It has nothing to do with implicit or explicit. The problem is simply the sequence in which the lines are executed within the method, which is top to bottom.
By the time it gets to your if/else in the "implicit" case, the three lines above, such as char firstChar = str.charAt(0); have already happened (or already failed). For an empty string it will blow up with a StringIndexOutOfBounds exception immediately on that line (look at the line number of the exception), and the method will stop executing then as it throws the exception out of the method. (The technical term for this is abrupt completion.) If that exception is thrown, the below if/else won't happen, so it cannot retroactively prevent the exception afterwards. That code will work fine if you move the three string-using statements from the top of the method to inside the 'if' branch of the if/else, so that they are not executed when not wanted.
In the "explicit" case, you added if (str.length() <= 1) return str; at the top of the method, where it can prevent the lines below from executing, because the return statement will exit the method before the attempts to use the non-existent characters of the string. That statement wouldn't help if it was lower down in the method.
I just want to add something about 'null', since other answerers on this page have complained that your code doesn't defend against a null argument. It's good to think about how your method will cope with peculiar input, but here, your code already does correctly defend against a null argument, because when you try to call charAt or length or substring on null, it will throw a NullPointerException out of the method, as it should.
Sometimes null should be checked for and allowed, but here it should not. If called without a valid string, what might frontBack be expected to return? Some might say it should return null, some might say it should return the empty string, and some might say it should coerce it to a string and thus return "luln". There is no fully sensible or unambiguously correct way to handle it that will work for all callers. So, frontBack should take the stance that null is not an acceptable input. Then it is the caller's fault if they pass in null, and if the caller passes in garbage, it's correct that they should get the garbage thrown back at them (metaphorically, of course; you will actually throw an exception object, not the original input) so they are forced to deal with it properly. Tolerating and making excuses for bad callers by explicitly coercing garbage to valid input is the wrong thing to do because it hides errors and it makes the program's behavior more subtle.
If the method had side effects, such as modifying a data structure, writing to a file, or calling other methods with side effects, then null input could be dangerous, because the method might complete some of the side effects without using str. Then, trying to use str would at some point throw the exception, leaving things half-finished and in an invalid state. Ideally, the side effects should be observed to happen either entirely or not at all. In that case, it would be good to check for null and throw the exception yourself at the top of the method:
if (str == null) throw new NullPointerException();
That won't make a difference in this simple method because it has no side effects (it is purely functional) and because it already unconditionally calls methods on str, which will cause the same exception to be thrown anyway.
Related
All I really need to know is if the function I am using is recursive or if the method simply doesnt get called within itself.
In my code, I have a helper function to reverse the second word and I put a toLowerCase in order to be able to compare words even if there are any random capitals.
Is this recursion or is it just a function that compares the two?
import java.util.Scanner;
public class isReverse {
public static void main(String[] args) {
isReverse rev = new isReverse();
Scanner in = new Scanner(System.in);
System.out.println("Please enter a word: ");
String a = in.nextLine();
System.out.println("Please Enter a second word to compare: ");
String b = in.nextLine();
System.out.println(rev.isReverse(a, b));
}
String rev = "";
public boolean isReverse(String wordA, String wordB){
String fword = wordA.replaceAll("\\s+", "").toLowerCase();
String clean2 = wordB.replaceAll("\\s+", "").toLowerCase();
String reverse = revString(clean2);
if(fword.length() == 0){
return false;
}
if (fword.equals(reverse)){
return true;
}
if (!reverse.equals(fword)){
return false;
}
else
return isReverse(fword,reverse);
}
public String revString(String sequence) {
String input = sequence;
StringBuilder order = new StringBuilder();
order.append(input);
order = order.reverse();
rev = order.toString();
return rev;
}
}
As far as your question is concerned, your code is not behaving like a recursive function because your code is not entering into the last else condition. For recursion to work you need to have:
a base case(if there is no base case the recursion will go on forever)
a recursive case(this is where you kind of reduce the original problem)
But my comment about your code:
If you're doing the actual reverse logic you don't need to use recursion just to check if the original string and the reverse string are the same. These is purely an algorithm problem so here is the way to solve the problem:
If the length of the given input is 1 then the reverse is the same.
else:
check the first and last chars of the string, if they are equal, then you need to remove those two chars and check if the rest of the string is a palindrome. This is the actual recursive step.
else the string is not a palindrome.
Technically? Well, you are calling a method from within itself, so, technically, yeah.
Pragmatically? No. The recursive call part will never be invoked.
Your code does this: I have 2 words. If the words are equal to each other, stop and do something. if they are not equal to each other, stop and do something. Otherwise, recurse.
And that's where it falls apart: It'll never recurse - either the words are equal, or they are not.
The general idea behind a recursive function is three-fold:
The method (java-ese for 'function') calls itself.
Upon each call to itself, the parameters passed are progressing to an end state - they become smaller or trend towards a stop value such as 0.
There are edge cases where the function does not call itself, and returns instead (the answer for the smallest/zero-est inputs does not require recursion and is trivial).
You're missing the #2 part here. Presumably, this is what you'd want for a recursive approach. Forget about revString, delete that entirely. Do this instead:
If both inputs are completely empty, return true (That's the #3 - edge cases part).
If one of the two inputs is empty but the other one is not, false. (Still working on #3)
If the first character of the input string is NOT equal to the last character of the output string, false. (Still #3).
Now lop the first char off of the first input and the last off of the latter (Working on #2 now - by shortening the strings we're inevitably progressing towards an end no matter what)
now call ourself, with these new lopped-down strings (That'll be #1).
That would be a recursive approach to the problem. It's more complicated than for loops, but, then, recursive functions often are.
Actually this is not a recursing. All you need is just:
Check that both string have the same length
Iteratively check letters from 0 to n from the first string and from n to 0 from the second string. If they equal, then go to the next iteration (recutsion) or return fail otherqwise.
// here do not check signature of the public method
public static boolean isReverse(String one, String two) {
return isReverse(one, 0, two, two.length() - 1);
}
// support method has two additional counters to check letters to be equal
private static boolean isReverse(String one, int i, String two, int j) {
if (i == one.length())
return j == -1;
if (j == two.length())
return i == -1;
// if not equal, then strings are not equal
if (one.charAt(i) != two.charAt(j))
return false;
// go to the next recursion to check next letters
return isReverse(one, i + 1, two, j - 1);
}
i need to get a string and rearrange it with recursion by getting char and by that char i have to move that char everywhere on the string to the end
like "Hello world!" ,'l' => "Heo word!lll"
i have problems understading the recursion way of thinking
so i started with this:
public static String ChToLast (String str, char ch){
if(str.indexOf(ch)== -1){
return str;
}else{
if(str.indexOf(0) == ch){
return str;
}
}
thank you for your help :)
Recursion is the practise of reusing your method inside itself. In this case, I will provide a solution to explain what happens:
public static String chrToLast(String str, char ch) {
//This if statement details the end condition
if(str.length() < 1) {
return "";
}
String newString = str.substring(1); //Create new string without first character
if(str.indexOf(ch) == 0) { //This happens when your character is found
return chrToLast(newString, ch) + ch;
} else { //This happens with all other characters
return str.charAt(0) + chrToLast(newString, ch);
}
}
If you execute:
chrToLast("Hello, World!", 'l')
This will result in the desired result: Heo, Word!lll
Process
In general, this method works by checking which character is currently the first in the given string, and then deciding what to do. If the first character is the same as the one your looking for (l), it will then remove that character from the string and use chrToLast on that new string. But, it also adds the character it found to the end of the result by using + ch. It continues to do this until there are no more characters left, which is what the end condition is for.
The end condition
The end condition returns an empty string "" because that is what is called the base case of the algorithm. You can think of a recursive algorithm as something solving a problem by calling itself a number of times. By calling themselves, recursive algorithms move towards a base. In this particular case, it does that by subtracting one character off the string each time the method is executed. Once there are no characters left, it reaches the base case which is "", where the string is finally empty and no characters can be subtracted anymore. (Hence it returns nothing as it's final state)
I hope this answers your question. It's important to understand this concept, as it is very powerful. Try to study the code and comment if something's not clear.
Something that can also help is by executing this code in an IDE and using the debugger to walk through its execution. You can then see for yourself what the flow of the program is, and see the value of the variables in play.
If you use recursion, it will be pretty expensive call for the result you are expecting. Lot of movement of String or charArray elements, eitherway you do. I don't see its a wiser choice. I would do it this way, it will be of space complexity O(2n) & performance complexity O(n).
public class Solve {
public static void main(String[] args) {
System.out.println(ChToLast("Hello world!", 'l'));
}
public static String ChToLast(String str, char ch) {
char[] chars = str.toCharArray();
char[] modChars = new char[chars.length];
int i = 0;
for(char element : chars){
if(ch != element){
modChars[i++] = element;
}
}
Arrays.fill(modChars, i, chars.length , ch);
return new String(modChars);
}
}
If you use while loop and write a method to check if that string means perfect statement then that may work for you
Here you would need some help of NLP concept to check everytime if arranged chars are making any statement or are grammatically correct.
This will help
This question already has answers here:
"Missing return statement" within if / for / while
(7 answers)
Closed 8 years ago.
I'm writing a method to find the upper case letters in a given string. I have this
public static String FindUpperCase (String x){
for (int i = x.length(); i>=0; i--){
if (Character.isUpperCase(x.charAt(i))){
return x.substring(i); }
}
But I'm getting an error thats telling me I must return a string. When I look up on the API what substring does it tells me that it returns a string that is a subset of the other string...which means I am returning a string, right? I was told that it was because I am returning a string within the loop and that's not the same thing but I'm a little confused by what this means because isn't the loop in the method? Does anyone know what I'm doing wrong or how I can fix this?
No, you're not always returning a string. What if the input is entirely lower case?
Basically, you need a return statement (or throw an exception) after the for loop, to handle the situation where you get to the end of it. Even in cases that you can reason that you'll never actually get to the end of the loop, the Java compiler follows strict rules for reachability, as specified in section 14.21 of the JLS. So even if your return statement were unconditional and we know that length() always returns a non-negative value, this still wouldn't compile:
public static String broken(String input) {
// *We* know that we'll always go into the body of the loop...
for (int x = input.length(); x >= 0; x--) {
return input;
}
// The end of the method is still reachable from the compiler's standpoint
}
The end of a non-void method can't be reachable - you must either throw an exception or return a value.
Also note that your initial value should be x.length() - 1 or x.charAt(i) will throw an exception. You should also change your method name to follow Java naming conventions.
Oh, and currently you're not returning "the upper case letters" - you're returning "everything from the last upper case character onwards" which is entirely different.
You are returning subjected to a condition, so if the condition is never true you are not returning. Try instead.
public static String FindUpperCase (String x){
for (int i = x.length() - 1; i>=0; i--){
if (Character.isUpperCase(x.charAt(i))){
return x.substring(i); }
return "";
}
Also Java is indexes start at 0, so your for sentence starts at x.length() - 1 (last position) or you will get StringIndexOutOfBoundsException
Consider the case when there's no uppercase in the given string, in that case, the function won't return anything.
So just after your for loop, you can return an empty string to make the function declaration valid.
Because you return string only if Character.isUpperCase(x.charAt(i)) is true. You have to return for example empty string if it is false.
public static String FindUpperCase (String x){
for (int i = x.length(); i>=0; i--){
if (Character.isUpperCase(x.charAt(i))){
return x.substring(i); }
}
return "";
}
Your problem is, that you are returning a string dependend on an if statement. You have to return a string or null in every possible case. Just place a return null or return "" at the last line of the function for a quick and dirty solution. Better would be to think what you want to return if no uppercase character is found.
I want to change the first method to a while and for loop. I have added the code below. Is this correct?
public String extractWordFour(String text){
if(text.length()==0 || text.charAt(0) == ''){
return "";
} else {
return text.charAt(0) + extractWordFour(text.substring(1));
}
}
public String extractWordFour(String text){
int i=0;
while (i<=text.length){
return text.charAt(0) + extractWordFour(text.substring(i));
i++;
}
}
public String extractWordFour(String text){
for(int i=0;i<=text.length();i++){
return text.charAt(0) + text.substring(1);
}
}
I'm not going to answer this question because I think its a h.w. assignment but I'm putting it in an answer since I can't fit this in a comment, but I'm assuming you want to convert a recursive solution into a while or for loop solution.
Your while solution is wrong first of all because you are mixing recursion and while together. You should not be calling the function inside your while loop!
public String extractWordFour(String text){
int i=0;
while (i<=text.length){
return text.charAt(0) + extractWordFour(text.substring(i));
i++;
}
}
This one can't finish because you are returning it before its even looped more than once.
public String extractWordFour(String text){
for(int i=0;i<=text.length();i++){
return text.charAt(0) + text.substring(1);
}
}
Anyways hope that helps. The best thing to do would be to fully understand what the first function does, write it down and then think about how to make it do the exact same thing with a while or a for loop.
For a start, you can't have String.charAt(0) == '' because '' isn't a valid character, unlike "" for an empty String which is valid.
Your second method doesn't work because it should be text.length() instead of text.length which is the method when you're calling it on an array, as well as the i++ being unreachable because of the recursion. And failing that, the method signature claims it returns a String, but there is no return statement.
Your third method does have a return statement, but it still wouldn't work because it'll just return on the first iteration and therefore only give you the first 2 characters (and in fact your compiler won't even allow it because it won't realise this).
Aside from all these issues, if the method name of extractWordFour is an accurate representation of what they should do, none of them will because the logic makes no sense. I suggest you start by thinking about that: How can you tell when one word ends by examining the String, and what does your program need to know to remove everything before the fourth word, and everything after it?
I have created this function to check abecedarian with while loop (A word is said to be "abecedarian" if the letters in the word appear in alphabetical order, such as "abdest")-
public static boolean isAbecedarian(String s) {
int index = 0;
char c = 'a';
while (index < s.length()) {
if (c > s.charAt(index)) {
return false;
}
c = s.charAt(index);
index = index + 1;
}
return true;
}
I want to change this function to a recursive function and I have written this function -
public static boolean isAbecedarianrec(String s){
char first = s.charAt(0);
char second = first ++;
if (first<second){
return isAbecedarianrec(s);
}
return false;
}
recursive function is not working as it should and I am not getting the expected result. Please check and help me to pin point the issue with this function.
Note - As I mentioned this is not a homework question and it is part of my self Java learning.
Two issues:
The following code char second = first++ should be char second = s.charAt(1);
The recursive call should be return isAbecedarianrec(s.substring(1));
Finally, you need length checks where appropriate. On method entry, ensure the string has at least 2 characters if not, return true.
When using recursion, you need to keep two things in mind. First, the input to the recursive should in some way be different than the previous input. Second, there must be a valid stopping point so that you don't recurse infinitely and thereby run out of memory.
Typically with recursion you need two things:
A base case (e.g. empty string, zero, etc.)
A way to check part of the more complex case, and then reduce it to a simpler recursive call.
The empty string does form a good base case here - it's trivially abecedarian. So the first part of your recursive method should be to check for the empty string and return true. This forms the base case that will be the termination of your recursive method in the "happy path" case.
Otherwise, you know you have a non-empty string. The recursive decomposition can be achieved by checking its first character, then recursively calling with the rest of the string. However, in order to perform the check, you'll need to remember what the previous character of the string was (just like c in the iterative method), so you'll need an additional argument to the recursive call to act as a sort of variable.
This is not uncommon with recursion - often the majority of the work is done in a "helper" method, and the public method just calls this with initial/dummy values.
Putting these together then, a solution would look something like the following:
// s must not be null
public boolean isAbecedarianrec(String s) {
return isAbecedarianRecImpl(s, (char)0);
}
private boolean isAbecedarianRecImpl(String s, char c) {
if (s.isEmpty())
return true;
else {
if (c > s.charAt(0))
return false;
else
return isAbecedarianRecImpl(s.substring(1), s.charAt(0));
}
}
Java does not have pointer arithmetics (it seems you are trying to do something like that). You code will take the first char (always the first char of the String), and afterwards it will increment the char (turning 'a' into 'b' etc) and furthermore store the value to second also. This means that first and second will always contain the same value.
A simple (but not very efficient solution could be:
public static boolean isAbecedarianrec(String s, char c){
if (s.equals("")) return true;
char first = s.charAt(0);
if (first>=c){
return isAbecedarianrec(s.subString(1), first);
}
return false;
}
(Notice that I have also flipped the equality. That seemed to be wrong).
Call the function with the value of the lowest character. E.g.: isAbecedarianrec(s, 'a').
Notice that this solution (like yours) requires that the code points of the letters have the same numerical order as the alphabetical order of the letters. That is not generally correct, for example you will see strange results if the string contains both capital and small letters.
To create a recursive function, you need two things: an end case that stops execution, and some way to modify the successive calls to the recursive function.
In your case, you have one end case covered (the case where the string is not abecedarian), but not the other. For your function to ever return true, it needs to contain a return true statement or a return statement with a boolean comparison in it. The condition in this case would probably be finding the end of the string (being called with an empty string).
You are also missing a modification of successive calls: every call to isAbecedarian is made with the same string. Depending on what works best in Java, you could either shorten the string by 1 character on every call, or pass the index as an argument to the function and increment it on each call.