The task is to shift a number within a string to the beginning of the string with a recursion. So if I feed "ba3nana" to the code it should return "3banana". Did some recursive tasks already but this one I am stuck on.
I tried I guess already 50 different combinations but so far my code only returns "banana3" so I go the opposite way with my number. Does anyone see the mistake in my code?
The call of the method looks like this:
System.out.println(shiftDigitLeft("ba3nana"));
This is the code so far:
private static String shiftDigitLeft(String text) {
if (text.isEmpty()) {
return text;
} else {
if (text.charAt(0) >= '\u0030' && text.charAt(0) <= '\u0039') {
return shiftDigitLeft(text.substring(1)) + text.charAt(0);
} else {
return text.charAt(0) + shiftDigitLeft(text.substring(1));
}
}
}
Thanks in advance!
The pseudocode for what you've written would look like this
String shiftDigitLeft(String text) {
if the text is empty
return empty
else
if the first character is a digit
return shiftDigitLeft(the rest of the string) + the digit
else
return the letter + shiftDigitLeft(the rest of the string)
}
It should be obvious from this that digits never get moved to the left, only to the right.
You should probably invert your approach so that you look whether the last character is a digit, and if it is then move it to the beginning.
Related
I am trying to learn Java, and now I'm trying algorithms. So, I'm stucked on recursion. I have a code that I don't understand.
public static String reverseString(String text){
// base case
if (text.length() == 0) {
return text;
}
else {
// recursive call
return reverseString(text.substring(1)) + text.charAt(0);
}
}
public static void main(String[] args) {
String str = new String("howdy");
// calling recursive function
String reverse = reverseString(str);
System.out.println(reverse); // Prints: ydwoh
}
Problem is that for me recursive call in this code for me is:
for the first time it retuns owdyh,
second time wdyo and so on.
I can't understand how the string ydwoh borns. I suspect that somewhere chars concotanating in the right order, and stored somewhere, but where is this place I also don't know.
UPDATE
I tried it with paper, what I got:
first recursive call:
return value owdyh = "owdy" + "h"
second call:
return value wdyo = "wdy" + "o"
and so on
The difficulty is the processing after the call. The first letter is added to the end of the result of reverseString of the rest.
reverseString "howdy"
reverseString "owdy"
reverseString "wdy"
reverseString "dy"
reverseString "y"
reverseString ""
return ""
return "" + "y"
returns "y" + "d"
returns "yd" + "w"
returns "ydw" + "o"
returns "ydwo" + "h"
returns "ydwoh"
It is like a mathematical proof by induction:
The empty string is reversed (result empty string).
When the recursive call works on a smaller string,
placing the first char at the end, also reverses the string.
So reverseString works for all length of strings.
Thanks for the answers! They helped me to figure out my misunderstanding!
What I couldn't understand is where all the chars from the text.charAt(0) are stored! The trick is that they are stored in the stack without any links. It's LIFO(Last-In-First-Out) approach in work.
I want to find out if a string that is comma separated contains only the same values:
test,asd,123,test
test,test,test
Here the 2nd string contains only the word "test". I'd like to identify these strings.
As I want to iterate over 100GB, performance matters a lot.
Which might be the fastest way of determining a boolean result if the string contains only one value repeatedly?
public static boolean stringHasOneValue(String string) {
String value = null;
for (split : string.split(",")) {
if (value == null) {
value = split;
} else {
if (!value.equals(split)) return false;
}
}
return true;
}
No need to split the string at all, in fact no need for any string manipulation.
Find the first word (indexOf comma).
Check the remaining string length is an exact multiple of that word+the separating comma. (i.e. length-1 % (foundLength+1)==0)
Loop through the remainder of the string checking the found word against each portion of the string. Just keep two indexes into the same string and move them both through it. Make sure you check the commas too (i.e. bob,bob,bob matches bob,bobabob does not).
As assylias pointed out there is no need to reset the pointers, just let them run through the String and compare the 1st with 2nd, 2nd with 3rd, etc.
Example loop, you will need to tweak the exact position of startPos to point to the first character after the first comma:
for (int i=startPos;i<str.length();i++) {
if (str.charAt(i) != str.charAt(i-startPos)) {
return false;
}
}
return true;
You won't be able to do it much faster than this given the format the incoming data is arriving in but you can do it with a single linear scan. The length check will eliminate a lot of mismatched cases immediately so is a simple optimization.
Calling split might be expensive - especially if it is 200 GB data.
Consider something like below (NOT tested and might require a bit of tweaking the index values, but I think you will get the idea) -
public static boolean stringHasOneValue(String string) {
String seperator = ",";
int firstSeparator = string.indexOf(seperator); //index of the first separator i.e. the comma
String firstValue = string.substring(0, firstSeparator); // first value of the comma separated string
int lengthOfIncrement = firstValue.length() + 1; // the string plus one to accommodate for the comma
for (int i = 0 ; i < string.length(); i += lengthOfIncrement) {
String currentValue = string.substring(i, firstValue.length());
if (!firstValue.equals(currentValue)) {
return false;
}
}
return true;
}
Complexity O(n) - assuming Java implementations of substring is efficient. If not - you can write your own substring method that takes the required no of characters from the String.
for a crack just a line code:
(#Tim answer is more efficient)
System.out.println((new HashSet<String>(Arrays.asList("test,test,test".split(","))).size()==1));
I currently have a method that is supposed to take two strings and then check if one string exists as a substring in other. It doesn't check both ways so the way in which I pass my strings to the method determines what string is looked for in the other.
Currently I am getting a stackoverflow error.
public boolean checkMatch(String text, String regex, int i){
int regexL = regex.length();
if(i == regexL){
return true;
}
System.out.println(text.charAt(i) + " " + regex.charAt(i));
if(text.charAt(i) == regex.charAt(i)){
return checkMatch(text, regex, i++);
}
else if(text.charAt(i) != regex.charAt(i)){
if(text.substring(1) == ""){
return false;
}
else if(text.substring(1) != ""){
return checkMatch(text.substring(1), regex, 0);
}
}
return false;
}
I am running a test using my first name as an example.
#Test public void test_52() {
assertEquals(true, checkMatch("Samual", "mu", 0));
}
the console looks like this after it overflows.
S m
a m
m m
m m
m m
etc
Where am I going wrong? Am I iterating wrong? The stack trace shows that it seems to be getting caught on this line.
return checkMatch(text, regex, i++);
But the defect point is rarely the point of failure. Sorry for the wall of text and code.
I don't know if the rest is correct, but here is one error: i++increments i after it was evaluated. You call your function with the same value every time. You probably mean ++i.
You have:
return checkMatch(text, regex, i++);
You mean:
return checkMatch(text, regex, ++i);
Or:
return checkMatch(text, regex, i + 1);
The problem with i++ there is post-increment evaluates to i before the increment, so you're just getting stuck without advancing i, and eventually the recursion overflows the stack.
Had you printed i in your debugging output, the problem may have been clearer.
You can just use the indexOf method:
System.out.println("Samual".indexOf("mu") > 0);
Output:
true
Hey I could use a little bit of help to figure out why my program isn't working. The question is to make a program using recursion that figures if it the text given is a palindrome or not after all the punctuation and white spaces are removed. While the program so far compiles, it returns every value as false. We are only allowed to change the isSymmetrical method. I could use whatever help possible trying to figure out how to make this work. Thank you.
public class StringSymmetry {
public static boolean isSymmetrical(String inputText)
{
if(inputText.length() == 0 || inputText.length() ==1)
return true;
if(inputText.charAt(0) == inputText.charAt(inputText.length()-1))
return isSymmetrical(inputText.substring(1,inputText.length()-1));
return false;
}
public static void main(String[] args) {
String[] sampleData =
{ "Don't nod",
"Dogma: I am God",
"Too bad - I hid a boot",
"Rats live on no evil star",
"No trace; not one carton",
"Was it Eliot's toilet I saw?",
"Murder for a jar of red rum",
"May a moody baby doom a yam?",
"Go hang a salami; I'm a lasagna hog!",
"Name is Bond, James Bond"
};
for (String s : sampleData)
{
System.out.println("isSymmetrical (" + s + ") returns " + isSymmetrical(s));
}
}
}
The problem is that you didn't include any checks for case or punctuation and white space.
One way you could do it is something like this. The specifics depend on what you're allowed to use for the assignment, but you're probably intended to do something along these lines.
Also, note that toLowerCase is problematic if you have the default locale set to something unusual like Turkey. For proper robustness, you need to specify a locale, but this isn't something you'll have to worry about in a homework assignment.
public static boolean isSymmetrical(String inputText)
{
inputText = inputText.toLowerCase();
if(inputText.length() == 0 || inputText.length() ==1)
return true;
if(!Character.isLetter(inputText.charAt(0)))
return isSymmetrical(inputText.substring(1,inputText.length()));
if(!Character.isLetter(inputText.charAt(inputText.length()-1)))
return isSymmetrical(inputText.substring(0,inputText.length()-1));
if(inputText.charAt(0) == inputText.charAt(inputText.length()-1))
return isSymmetrical(inputText.substring(1,inputText.length()-1));
return false;
}
Check the following function:
public static boolean isPalindrome(String str, int x) {
if(x == 0) return true;
if(str.charAt(0) == str.charAt((str.length() - 1)))
return isPalindrome(str.substring(1, str.length() - 1), x - 1);
return false;
}
Explanation:
A recursive function with the following parameter's:
str - a String object which will be tested for symmetry.
x - Integer that represent's the recursive tester parameter and decides for how far you want to iterate and check for two sided symmetry.
The base case is set to zero and return's true when you finished the desired iteration number.
The second if-condition statement is used to check the corner's of the string that is given, and its return statement will recursively enter another testing loop with shorter corner's of the original String( . . . corner's will be shorter by one).
First of all I am not asking for people to "do my homework" like I have seen others on here ask for. I have managed to code a working iterative version of a program that determines if a string is a palindrome or not. Spaces, punctuation and special characters are ignored while determining if the string is a palindrome. This version does work but when I try and apply recursive statements in the "isPalindrome()" method I get Stack Overflow errors. I know what these errors are, it's just that applying a recursive method in a program like this is quite hard for me to get my head around (I only got taught about them 2 weeks ago). Anyway here is the code I have managed to compile (and run) so far:
/** Palindrome.java: A sigle application class that determines if a word or a string
* is a palindrome or not. This application is designed to ignore spaces between
* chars, punctuation marks and special characters while determining if the word or
* string is a palindrome or not.
*
**/
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.*;
public class Palindrome{
static String palindrome, str, str2, str3;
/** The main method of the Palindrome application. Takes input from the
* user, removes spaces from their input, turns their string input into
* lowercase and then all non letter characters are taken out of the user's
* input. Finally the recursive method determines if the string entered in
* by the user is a palindrome.
*
* #param args Takes in a string array of arguements
**/
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
str = removeSpaces(input.nextLine());
str2 = str.toLowerCase();
str3 = normalise(str2);
}
System.out.println(isPalindrome(str3));
}
/** The default constructor
**/
public Palindrome(){
}
/** isPalindrome(): A boolean method that is passed through a String input
* and uses a for loop, two inner while loops and an if-else to determine
* whether the users input is a palindrome.
*
* #param s The string input to be tested
* #return true The users input is a palindrome
* #return false The users input isn't a palindrome
**/
public static boolean isPalindrome(String s){
int first, last;
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
first++;
}
while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
last--;
}
}
if( first > last || s.charAt(first) != s.charAt(last) ){
//return isPalindrome(s.substring(0, s.length()-1)) == false;
return false;
}
else{
//return isPalindrome(s.substring(0, s.length()-1)) == true;
return true;
}
}
/**
* This method takes out punctuation marks in the string parsed
* through, using Java's regular expressions (regex) and Java's
* inbuilt method replaceAll(). The regex expression is passed
* through the replaceAll() method to remove all non alpha-numeric
* characters from the string passed through the method's parameter.
*
* #param t The string that will have punctuation stripped from it.
*
* #return t The string has had all non alpha-numeric characters
* removed and the new string is then returned.
*/
public static String normalise(String t){
t = t.replaceAll("[^a-zA-Z0-9]", "");
return t;
}
/** removeSpaces(): A method that deletes spaces from the users input
* and then decrements the string length count so any indexes aren't missed
* when it is incremented.
*
* #param s The string which is going to have it's spaces removed.
* #return temp The new string is then returned after the spaces have been taken out.
**/
public static String removeSpaces(String s){
StringBuilder temp = new StringBuilder(s); //creates a new StringBuilder with the inputted String
for(int i = 0; i < temp.length(); i++){ //do this for the entire length of the StringBuilder
if(temp.charAt(i) == ' '){ //if the char at i is a space
temp.deleteCharAt(i); //remove the char
i--; //subtract 1 from the counter so we don't miss an index when we increment it
}
}
return temp.toString(); //return the new String
}
}
I have blanked out the recursive statements in the recursive method for now. If someone can tell me what exactly I have done wrong and also help me in implementing a solution that would be really good. I would rather stick with the iterative version because I understand the mechanics of it, but have been asked to do a recursive version (I have been Java coding since after my mid year break last year but am a relative novice at recursion) which is proving to be quite a challenge. If you alter the code and it ends up working with the recursive version please explain how, when, why etc with your alterations. Am not looking for someone to just do this for me, I'm wanting to learn and it seems that I have learned best by example (I did get a B pass last year by analysing examples and reading explanations of implementations). Many thanks :).
EDIT: I think I have got the recursion going ok now, just the logic is the thing confusing me at the moment. Here is the recoded version of the isPalindrome() method:
public static boolean isPalindrome(String s){
int first, last;
boolean isPalindr = true;
if (s.length() <= 1){
return true; // Base case
}
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
// while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
// first++;
// }
// while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
// last--;
// }
// }
if( first == last || s.charAt(first) == s.charAt(last) ){
//return isPalindrome(s.substring(first, last));
return isPalindrome(s.substring(first, last)) == true;
//isPalindr = false;
}
else{
return isPalindrome(s.substring(first, last)) == false;
//isPalindr = true;
}
}
return isPalindr;
}
If someone can help me with the logic I think this will be fixed :).
Removing all of the code that has nothing to do with the problem leaves us with this:
public static boolean isPalindrome(String s){
for loop {
isPalindrome();
}
}
isPalindrome calls isPalindrome calls isPalindrome, etc... infinitum.
The difference between this and a proper recursive function is that a recursive function will have some sort of conditional statement, breaking the cycle of the function calling itself. The flow of execution will go like this:
isPalindrome(1) begins execution and calls isPalidrome(2)
isPalindrome(2) begins execution and calls isPalidrome(3)
isPalindrome(3) begins execution and calls isPalidrome(4)
isPalindrome(4) begins execution and calls isPalidrome(5)
isPalindrome(5) begins execution and returns to isPalindrome(4)
isPalindrome(4) resumes execution and returns to isPalindrome(3)
isPalindrome(3) resumes execution and returns to isPalindrome(2)
isPalindrome(2) resumes execution and returns to isPalindrome(1)
isPalindrome(1) resumes execution and returns.
If that explanation doesn't help, think of it like this. Suppose someone was handing you plates, one at a time, to see if you can hold 25 plates at a time. It would go something like this:
Plate 1 is given to you. Are there 25 plates? No. Add another plate.
Plate 2 is stacked on top of Plate 1. Are there 25 plates? No. Add another plate.
Plate 3 is stacked on top of Plate 2. Are there 25 plates? No. Add another plate.
...
Plate 24 is stacked on top of Plate 23. Are there 25 plates? No. Add another plate.
Plate 25 is stacked on top of Plate 24. Are there 25 plates? Yes. Mission Accomplished. Now, let's put the plates back.
Plate 25 is removed.
Plate 24 is removed.
...
Plate 3 is removed.
Plate 2 is removed.
Plate 1 is removed.
Here's how that might be coded:
bool stackPlates(int i){
plateStack.addPlate();
if (plateStack.wasDropped == true) { return false; } // Were the plates dropped? Return FALSE to indicate failure.
else if (i < 25) { return stackPlates(i+1); } // Are there 25 plates yet? If not, add another.
else { return true; } // There are 25 plates stacked. Return TRUE to indicate success.
plateStack.removePlate(i);
}
Here's stackPlates(int i) called from another function:
bool success = stackPlates(1);
if (success==TRUE) { cout << "CONGRATULATIONS! YOU STACKED 25 PLATES!"; }
else { cout << "YOU BROKE THE PLATES! BETTER LUCK NEXT TIME!"; }
What your function needs to do in order to work properly is do this:
bool isPalindrome(string s, int i) {
char first = s[i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
char last = s[(s.length -1) -i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
if ( first != last ) { return false; } // return false if mismatch letter
else if ( i >= (s.length/2) ) { return true; } // return true if string fully checked
else { return isPalindrome(s, i+1); } // string not fully checked; move to next letter
}
You're experiencing stack overflows because the else branch at the bottom of the function is executed when (first <= last && "characters are equals"), so you keep recurring on the case where your string is composed by one character.
By the way, I think your code is not using recursion cleanly: you should preprocess your string only one time before starting recurring on the string, and the code that performs the palindrome recursion should be far simpler.
For any given entry into isPalindrome, it's going to recursively call itself regardless because you have no condition on your else. So, if it meets the criteria "first > last || s.charAt(first) != s.charAt(last)", it's going to recursively call isPalindrome, then the next call is too, even if it hits the else.
I don't know what a Palindrome is or what the real solution to the problem is, but that's why you're getting the stack overflow error. I suspect you need to add another condition to your else such that it will stop recursively calling itself.
When writing a recursive function the best way to go about this is usually to decide on a base case (:like "" is a palindrome, though so is "a" ... ) and then devise a method to take any state and move it to the base case.
So in the case of the palindrome, it's the same basic idea as before, if the first character and the last character are the same you return true and check the rest of the string ( thus moving closer to the base case ) and if they are not then you return false.
Your stack overflow comes from calling isPalindrome in every case rather than when you need to continue solving the problem, don't forget that if two characters mean that something isn't a palindrome, the rest is rendered irrelevant ( and thus needn't be recursed on )
Your recoded version is a bit strange, because it's still using a loop when it doesn't need to. In particular, your code will never go beyond the first iteration in your loop, because in the embedded if-else statement, you're going to return a result no matter what, so your function will always exit during the first iteration (unless there are no iterations at all).
Recursion should be approached by
Identifying a base case, i.e. a simplest case that can be solved
Re-representing a larger problem as a partial solution followed by the same, but smaller problem.
The base case you've handled correctly; any String which is length 1 or less is automatically a Palindrome.
The next step is to consider a larger problem, perhaps some string abcwewe....ba. How can we break this down into a simpler problem? We know that we'd normally check whether something is a palindrome by checking the letters one by one in pairs, starting at the ends, but then we also realise that each time we check the letters, we just repeat the same problem again and solve it the same way.
In the string I gave above, we check and verify that the first letter a is the same as the last letter a, so that's kind of a partial solution. Now we we end up with is the smaller word bcwewe....b, and it's the same problem again: Is this new String a palindrome also?
Thus, all you have to do now is to invoke the recursive call, but this time with the substring beginning with the 2nd character to the 2nd to last character. You can code the answer in just two lines, as below:
public static boolean isPalindrome(String s) {
if (s.length() <= 1) return true; // base case
return s.charAt(0) == s.charAt(s.length()-1) && isPalin(s.substring(1,s.length()-1)); // recursive case
}
One point to note is that I'm using the short circuit &&, so if the first condition fails (checking first and last character), then Java will not invoke the recursion.