recursion method not returning a string - java

I have to create a code that can find the longest palindrome contained inside sentences. (eg. Some people like cake but I prefer pie; the longest palindrome is i prefer pi). The problem is that upon running the code it doesn't return the palindrome. I'm not sure what the problem is but if anyone can figure it out I'd appreciate you letting me know. Thanks!
Code is below...
public class Recursion6 {
static String recursion(String word, int currentLength, int x, String substring) {
String reverse =new StringBuffer(word).reverse().toString();
if(word.length() == 1 ){
return substring;
}
if(word.charAt(0) != word.charAt(x)) {
if(x == word.length() - 1) {
recursion(word.substring(1), currentLength, 1, substring);
}
x++;
recursion(word, currentLength, x, substring);
} else {
if(word.substring(0, x + 1).equalsIgnoreCase(reverse.substring(word.length() - (x+1), word.length()))) {
if(word.substring(0, x).length() > currentLength) {
currentLength = word.substring(0, x + 1).length();
substring = word.substring(0, x + 1);
}
recursion(word.substring(1), currentLength, 1, substring);
}
recursion(word.substring(1), currentLength, 1, substring);
}
return substring;
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("Enter a Sentence:");
String word=sc.nextLine();
System.out.println("The Palendrome is "+recursion(word.replaceAll(" ", ""), 1, 1, null));
sc.close();
}
}

You ignore the return value.
For example:
recursion(word, currentLength, x, substring);
There's a return value, all right. You just do nothing with it for the recursive calls. What gets returned from the outermost call is just the input to the outermost call, which is a null string.
You probably need to review how recursive activation works. The 'return' statement only returns from the current level, it does not empty the entire call stack.

Here's another approach.
First, just get all the substrings on the stack. That's what the first two recursive calls do.
Then just check each substring as the stack unwinds to see if it is a palindrome.
the private method does the actual check. It simply compares characters at both ends towards the middle.
Final output may contain white space and/or punctuation characters.
public static void main(String[] args) {
String s =
"Some people like radar, others " +
"like a man, a plan, a canal, panama!, but " +
"my favorite is 'I prefer pie'";
String res = findLongestPalindrome(s,0,s.length());
System.out.printf("'%s'%n", res);
prints
' a man, a plan, a canal, panama!, '
The method takes the string, and starting and ending indices.
public static String findLongestPalindrome(String s, int start, int end) {
String save = "";
if (end - start > 0) {
save = findLongestPalindrome(s, start + 1, end);
} else if (end > 1) {
save = findLongestPalindrome(s, 0, end - 1);
}
String temp;
if (isPalindrome(temp = s.substring(start, end))) {
if (temp.length() > save.length()) {
save = temp;
}
}
return save;
}
// iterates from the ends toward the middle.
private static boolean isPalindrome(String s) {
s = s.replaceAll("\\W+", "").toLowerCase();
int end = s.length();
for (int i = 0; i < s.length() >> 1; i++) {
if (s.charAt(i) != s.charAt(--end)) {
return false; // fast fail if any two are not equal
}
}
return true;
}

Related

Repeating a string with recursion, beginner

I'm supposed to write a simple method that returns given string for given amount, seperated by comma (and no comma in the end), with recursion. If there are less than two counts, the return is empty string "".
final static String COMMA = ", ";
public static String replicate(String s, int count) {
String answer = "";
if (count < 2) {
return answer;
}
else {
answer = s + COMMA + replicate(s, (count - 1));
return answer;
}
}
If I put s = cat and count = 5, I get cat, cat, cat, cat,- One short what I need.
I'm at my wits end here what to do, to get proper amount of repeats here without the comma at the end.
EDIT: Clearly I failed to communicate, that the method SHOULD return an empty string, if the count is two or less. Sorry for the lack of clarity there.
You're extremely close! When you hit your base case count < 2, instead of returning an empty string, you can return your input string. Be sure to check that length isn't 0, too.
EDIT: from information in the comments, you want to return an empty string for any counts less than or equal to two. Odd requirement, but this will fit that issue; it uses three as a base case instead of two, returning three s inputs concatenated together.
final static String COMMA = ", ";
public static String replicate(String s, int count) {
String answer = "";
if(count <= 2) {
return answer;
}
if(count == 3) {
return (s + COMMA + s + COMMA + s);
}
else {
answer = s + COMMA + replicate(s, (count - 1));
return answer;
}
}
Demo
Every element is there, just a bit unreadable code.
If count is 0, "".
If one, s itself.
Otherwise s, + recursive result.
So:
public static String replicate(String s, int count) {
if (count <= 0) {
return "";
} else if (count == 1) {
return s;
} else {
return s + COMMA + replicate(s, count - 1);
}
}
What lead to mental failure was the variable answer, and the two cases of < 2.
public static String replicate(String s, int count) {
if (count >= 2) {
s = s + COMMA + replicate(s, --count);
}
return s;
}
replicate("hii", 4) --> return "hii,hii, hii, hii"
COMMA + replicate("hii", 3) --> return "hii, hii, hii"
COMMA + replicate("hii", 2) --> return "hii, hii"
COMMA + replicate("hii", 1) --> return "hii"

How to avoid StackOverFlow in recursion?

I need to find the frequency of each character in a String using recursion.
Found this question online and wanted to do this as a challenge.
Have used two variables 'a' and 'i', where 'a' is used to store the index of the current character in the string that needs to be searched and 'i' is used to go through the entire string in search of the character that 'a' has extracted.
Finding the frequency of each character present in the word.
import java.util.*;
public class ini {
public static void main(String args[]) {
recur(0, 0, "Hello how are you", 0);
}
static private char m = ' ';
private static boolean recur(int a, int i, String s, int count) {
if (s.length() >= 1) {
if (a < s.length()) {
m = s.charAt(a);
if (i < s.length()) {
if (s.charAt(a) == s.charAt(i)) {
count += 1;
}
recur(a, ++i, s, count);
}
i = 0;
System.out.println(s.charAt(a) + ":" + count);
s = s.replaceAll(Character.toString(s.charAt(a)), "");
a += 1;
count = 0;
}
if (a != s.length() - 1) {
recur(a, i, s, count);
}
} else {
return false;
}
return true;
}
}
The current output ignores the letter "w" altogether
H:1
l:2
:3
o:3
r:1
y:1
Exception in thread "main" java.lang.StackOverflowError
at ini.recur(ini.java:26)
at ini.recur(ini.java:26)
at ini.recur(ini.java:26)
at ini.recur(ini.java:26)
at ini.recur(ini.java:26)
at ini.recur(ini.java:26)
at ini.recur(ini.java:26)
at...
There are a couple of things that we don't know:
Should h and H be considered only one character?
Should you count the spaces? (Programmatically speaking, space is a character)
Do you need an improved solution?
Are you allowed to do manipulate the initial text?
Some observations:
You need to rename your variables better
You don't need the static field
You don't need the recursive function to be boolean
a is used only for the identification of the character, and the increment is not needed
Quick solution:
private static void recur(int startingIndex, int recursionIndex, String text, int count) {
if (text.length() >= 1) {
if (startingIndex < text.length()) {
char currentCharacter = text.charAt(startingIndex);
if (recursionIndex < text.length()) {
if (currentCharacter == text.charAt(recursionIndex)) {
count += 1;
}
recur(startingIndex, ++recursionIndex, text, count);
} else {
System.out.println(currentCharacter + ":" + count);
text = text.replace(Character.toString(currentCharacter), "");
recur(0, 0, text, 0);
}
}
}
}
Improved solution:
public class Main {
public static void main(String[] args) {
recur(0, "Hello how are you", 0);
}
private static void recur(int index, String text, int count) {
if (text.length() >= 1) {
char currentCharacter = text.charAt(0);
if (index< text.length()) {
if (currentCharacter == text.charAt(index)) {
count += 1;
}
recur(++index, text, count);
} else {
System.out.println(currentCharacter + ":" + count);
text = text.replace(Character.toString(currentCharacter), "");
recur(0, text, 0);
}
}
}
}
The optimal solution without modifying the initial text:
private static int recur(char character, String text, int index) {
if (index >= text.length()) {
return 0;
}
int count = text.charAt(index) == character? 1 : 0;
return count + recur(text, character, index + 1);
}
After much tinkering I've figured it out. Basically you should not increment a. This will skip over letters and thus remove the line where a is incremented.a += 1; Furthermore, with recursion (I was struggling to remember myself) you want to be careful how you call the function you are in. If you don't make the recursive call as the last step (tail recursion), you will enter an infinite loop for various reasons here. All you need to do is add a return statement before the first recursive call and you will have solved it like so.
import java.util.*;
public class ini {
public static void main(String args[]) {
recur(0, 0, "Hello how are you", 0);
}
static private char m = ' ';
private static boolean recur(int a, int i, String s, int count) {
if (s.length() >= 1) {
if (a < s.length()) {
m = s.charAt(a);
if (i < s.length()) {
if (s.charAt(a) == s.charAt(i)) {
count += 1;
}
//Added crucial return statement
return recur(a, ++i, s, count);
}
i = 0;
System.out.println(s.charAt(a) + ":" + count);
s = s.replaceAll(Character.toString(s.charAt(a)), "");
//removed a += 1;
count = 0;
}
if (a != s.length() - 1) {
recur(a, i, s, count);
}
} else {
return false;
}
return true;
}
}
Output :
H:1
e:2
l:2
o:3
:3
h:1
w:1
a:1
r:1
y:1
Here is a link about tail vs. head recursion : Tail vs. Head Recursion
Hope this helps you!
My approach is slightly different from yours but you might find it interesting.
In my approach I am removing the character and checking the difference in the length of String. The change in length would be the times that character repeated. Rest is explained in the code.
public class CharactersFrequency {
public static void main(String[] args) {
CharactersFrequency cF = new CharactersFrequency();
long startTime = System.currentTimeMillis();
// I generated a sting with 1000 characters from a website
cF.frequencyOfCharacters("a quick brown fox jumps over the lazy dog");
long endTime = System.currentTimeMillis();
System.out.println("Runtime: " + (endTime - startTime) + " ms");
}
private void frequencyOfCharacters(String input) {
CharactersFrequency cF = new CharactersFrequency();
cF.frequencyOfCharactersRec(input, input.charAt(0) + "");
}
public void frequencyOfCharactersRec(String input, String currentChar) {
// If only one char is left
if (input.length() <= 1) {
System.out.println(currentChar + ": 1");
} else {
// Checking Initial length and saving it
int inputOldLength = input.length();
// Removing the char whose frequency I am checking
input = input.replace(currentChar, "");
// Checking new length
int inputNewLength = input.length();
// The difference between length should be the number of times that char
// repeated
System.out.println(currentChar + " : " + (inputOldLength - inputNewLength));
// In some cases after replace function the string becomes empty
// thus charAt(0) gives an error
if (inputNewLength > 0) {
frequencyOfCharactersRec(input, input.charAt(0) + "");
}
}
}
}
Output:
a : 2
: 8
q : 1
u : 2
i : 1
c : 1
k : 1
b : 1
r : 2
o : 4
w : 1
n : 1
f : 1
x : 1
j : 1
m : 1
p : 1
s : 1
v : 1
e : 2
t : 1
h : 1
l : 1
z : 1
y : 1
d : 1
g: 1
Runtime: 3 ms

Make The All of Combination from Palindrome

I have a problem for my task. I must make a program that the input is a palindrome / not a palindrome, and the output is return the substring of the string that can be a palindrome in recursive. Example :
"marah" , the output should be, ("m","a","r","a","h") , ("m","ara","h") . I dont know to implement this in recursive. Please anyone who can help me, i'm very need that code. I worked it in java. Thank you, i hope there is a help coming :D .
public static String palindrome(String s) {
String s, sub;
int i, c, length;
Scanner in = new Scanner(System.in);
System.out.println("Enter a string to print it's all substrings");
s = in.nextLine();
length = string.length();
System.out.println("Substrings of \"" + string + "\" are :-");
for (c = 0; c < length; c++) {
for (i = 1; i <= length - c; i++) {
sub = string.substring(c, c + i);
System.out.println(sub);
}
}
}
public static String longestPalindrome(String s) {
if (s.isEmpty()) {
return null;
}
if (s.length() == 1) {
return s;
}
String longest = s.substring(0, 1);
for (int i = 0; i < s.length(); i++) {
// get longest palindrome with center of i
String tmp = helper(s, i, i);
if (tmp.length() > longest.length()) {
longest = tmp;
}
// get longest palindrome with center of i, i+1
tmp = helper(s, i, i + 1);
if (tmp.length() > longest.length()) {
longest = tmp;
}
}
return longest;
}
// Given a center, either one letter or two letter,
// Find longest palindrome
public static String helper(String s, int begin, int end) {
while (begin >= 0 && end <= s.length() - 1 && s.charAt(begin) == s.charAt(end)) {
begin--;
end++;
}
return s.substring(begin + 1, end);
}
if the input is "mama", the output is only "ama", the expected is, "m","a","m","a" , "mam","a" , and "m","ama" . Anybody can help?
This is called palindrom partition, you can find it here http://www.programcreek.com/2013/03/leetcode-palindrome-partitioning-java/

Recursively swap pairs of letters in a string in java

For example, if I call exchangePairs("abcdefg"), I should receive "badcfeg" in return.
This is for a homework assignment, any kind of pseudocode would be very helpful. I am just beginning to learn recursion and up until this problem I haven't had too much of an issue.
public String swapPairs(String s) {
if (s.length() < 2)
return s;
else
return swap(s.charAt(0), s.charAt(1)) + swapPairs(s.substring(2));
}
You're not just beginning to learn recursion, because recursion is part of your everyday live. You just don't notice, because it is so normal and nobody calls it recursion.
For example, you watch a movie on TV, and in one scene there is someone watching a movie on TV.
In programming, recursion is a way to make hard things easy. Always start with the easy case:
What is the result of exchangePairs("")?
What is the result of exchangePairs("x") where x is any character?
Suppose you have already completed exchangePairs(), how would the result be for "xy..." where "..." is any string? Surely "yx+++", where "+++" is the result of exchangePairs("...").
Now, it turns out that we've covered all cases! Problem solved!
Such is the greatness of recursion. You just use your function as if it were complete despite you've not completed it yet.
Why use recursion?
for (int i = 0; i + 1 < strlen(str); ++i) {
char tmp = str[i + 1];
str[i + 1] = str[i];
str[i] = tmp;
}
If you have to use recursion, I suppose you could do something like this:
char* exchangePairs(char* str) {
if (strlen(str) >= 2) {
// if there are characters left, swap the first two, then recurse
char tmp = str[1];
str[1] = str[0];
str[0] = str[1];
exchangePairs(str + 2);
}
return str;
}
That's in C, but it should give you the idea (I'm better in C and didn't want to just give you a copy/pasteable solution).
Use tail recursion
String reverse(String input)
{
if(String.length()==1)
{
return input;
}
else
{
return reverse(input,"");
}
}
String reverse(String input, String result)
{
if(input.length == 0) return result;
else return result(input.substring(1),input.charAt(0) + result);
}
Ok Here is my solution. I dont have Java at my disposal so I did it in C# which is very similar to Java so should be easy to understand/port;
public static char[] exchangePairs(char[] charArray, int current)
{
if(current >= charArray.Length - 1)
{
return charArray;
}
char nextChar = charArray[current + 1];
char currentChar = charArray[current];
charArray[current] = nextChar;
charArray[current + 1] = currentChar;
int i = current + 2;
return exchangePairs(charArray, i);
}
Call to the method:
exchangePairs("abcdefghij".ToCharArray(), 0);
public static String swapPairs(String s) {
String even = "";
String odd = "";
int length = s.length();
for (int i = 0; i <= length-2; i+=2) {
even += s.charAt(i+1) + "" + s.charAt(i);
}
if (length % 2 != 0) {
odd = even + s.charAt(length-1);
return odd;
} else {
return even;
}
}
A small adding on Steven's solution, you can use StringBuffer/StringBuilder.reverse() for reversing a string.
public String swapPairs(String s) {
if (s.length() < 2)
return s;
else {
return new StringBuffer(s.substring(0, 2)).reverse().toString() + swapPairs(s.substring(2));
}
}
I'd introduce an integer recursion control variable which is how much of the string has already been exchanged. At each level, check the control variable to see if there's more to do and, if so, exchange the next pair, increment by 2, and recurse.

Concatenate two strings without intersection

I need to concatenate two string in another one without their intersection (in terms of last/first words).
In example:
"Some little d" + "little dogs are so pretty" = "Some little dogs are so pretty"
"I love you" + "love" = "I love youlove"
What is the most efficient way to do this in Java?
Here we go - if the first doesn't even contain the first letter of the second string, just return the concatenation. Otherwise, go from longest to shortest on the second string, seeing if the first ends with it. If so, return the non-overlapping parts, otherwise try one letter shorter.
public static String docat(String f, String s) {
if (!f.contains(s.substring(0,1)))
return f + s;
int idx = s.length();
try {
while (!f.endsWith(s.substring(0, idx--))) ;
} catch (Exception e) { }
return f + s.substring(idx + 1);
}
docat("Some little d", "little dogs are so pretty");
-> "Some little dogs are so pretty"
docat("Hello World", "World")
-> "Hello World"
docat("Hello", "World")
-> "HelloWorld"
EDIT: In response to the comment, here is a method using arrays. I don't know how to stress test these properly, but none of them took over 1ms in my testing.
public static String docat2(String first, String second) {
char[] f = first.toCharArray();
char[] s = second.toCharArray();
if (!first.contains("" + s[0]))
return first + second;
int idx = 0;
try {
while (!matches(f, s, idx)) idx++;
} catch (Exception e) { }
return first.substring(0, idx) + second;
}
private static boolean matches(char[] f, char[] s, int idx) {
for (int i = idx; i <= f.length; i++) {
if (f[i] != s[i - idx])
return false;
}
return true;
}
Easiest: iterate over the first string taking suffixes ("Some little d", "ome little d", "me little d"...) and test the second string with .startsWith. When you find a match, concatenate the prefix of the first string with the second string.
Here's the code:
String overlappingConcat(String a, String b) {
int i;
int l = a.length();
for (i = 0; i < l; i++) {
if (b.startsWith(a.substring(i))) {
return a.substring(0, i) + b;
}
}
return a + b;
}
The biggest efficiency problem here is the creation of new strings at substring. Implementing a custom stringMatchFrom(a, b, aOffset) should improve it, and is trivial.
You can avoid creating unnecessary substrings with the regionMatches() method.
public static String intersecting_concatenate(String a, String b) {
// Concatenate two strings, but if there is overlap at the intersection,
// include the intersection/overlap only once.
// find length of maximum possible match
int len_a = a.length();
int len_b = b.length();
int max_match = (len_a > len_b) ? len_b : len_a;
// search down from maximum match size, to get longest possible intersection
for (int size=max_match; size>0; size--) {
if (a.regionMatches(len_a - size, b, 0, size)) {
return a + b.substring(size, len_b);
}
}
// Didn't find any intersection. Fall back to straight concatenation.
return a + b;
}
isBlank(CharSequence), join(T...) and left(String, int) are methods from Apache Commons.
public static String joinOverlap(String s1, String s2) {
if(isBlank(s1) || isBlank(s2)) { //empty or null input -> normal join
return join(s1, s2);
}
int start = Math.max(0, s1.length() - s2.length());
for(int i = start; i < s1.length(); i++) { //this loop is for start point
for(int j = i; s1.charAt(j) == s2.charAt(j-i); j++) { //iterate until mismatch
if(j == s1.length() - 1) { //was it s1's last char?
return join(left(s1, i), s2);
}
}
}
return join(s1, s2); //no overlapping; do normal join
}
Create a suffix tree of the first String, then traverse the tree from the root taking characters from the beginning of the second String and keeping track of the longest suffix found.
This should be the longest suffix of the first String that is a prefix of the second String. Remove the suffix, then append the second String.
This should all be possible in linear time instead of the quadratic time required to loop through and compare all suffixes.
The following code seems to work for the first example. I did not test it extensively, but you get the point. It basically searches for all occurrences of the first char of the secondString in the firstString since these are the only possible places where overlap can occur. Then it checks whether the rest of the first string is the start of the second string. Probably the code contains some errors when no overlap is found, ... but it was more an illustration of my answer
String firstString = "Some little d";
String secondString = "little dogs are so pretty";
String startChar = secondString.substring( 0, 1 );
int index = Math.max( 0, firstString.length() - secondString.length() );
int length = firstString.length();
int searchedIndex = -1;
while ( searchedIndex == -1 && ( index = firstString.indexOf( startChar, index ) )!= -1 ){
if ( secondString.startsWith( firstString.substring( index, length ) ) ){
searchedIndex = index;
}
}
String result = firstString.substring( 0, searchedIndex ) + secondString;

Categories