Using recursion to test if two strings are the same but reversed - java

For my assignment I have to use recursion to test if two strings are the same but reversed.
Here is the actual question:
Write a recursive method called isStringReversed which, given two String parameters, returns true if the two strings contain the same sequence of characters but in reverse order (ignoring capitalization), and false otherwise. For example, isStringReversed("piano", "oNaIp") would return true. Note: the null (empty) string and string of one letter are both the reverse of themselves.
Here's what I have made, but when I execute the program, i always get
a false return. Heres my code:
public static boolean isStringReversed(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() == 1 || s2.length() == 1) {
return true;
}else if (s1.length() != s2.length()) {
return false;
}else {
char s1first = Character.toLowerCase(s1.charAt(0));
char s2last = Character.toLowerCase(s2.charAt(s2.length() - 1));
if (s1first == s2last){
String s1shorter = s1.substring(0, s1.length() - 1);
String s2shorter = s2.substring(0, s2.length() - 1);
return isStringReversed(s1shorter, s2shorter);
}else {
return false;
}
}
}

When doing substring on s1first, you should remove the first character, not the last.
Just one line above that you compare first character of s1first and last character of s2last. So once you establish that they are equal, that's what you remove and continue the recursion.

Instead of
String slshorter = sl.substring(0, s1.1ength() - l) ;
String s2shorter = s2.substring(0, s2.1ength() - l) ;
use
String slshorter = sl.substring(1) ;
String s2shorter = s2.substring(0, s2.1ength() - 1) ;
Note that the second parameter of the method substring() means to that index exclusive.

This is the recursive idea
public static bool isStringReversed(string input1, string input2)
{
string s1 = input1.ToLower();
string s2 = input2.ToLower();
if(s1 == null && s2 == null)
return true;
if (s1.Length == 1 && s2.Length == 1)
{
if (s1 == s2)
return true;
return false;
}
if (s1.Length != s2.Length)
return false;
return isStringReversedRec(s1, s2, s1.Length - 1, 0);
}
private static bool isStringReversedRec(string s1, string s2, int indexS1, int indexS2)
{
if (indexS1 < 0)
return true;
if (s1.charAt(indexS1) != s2.charAt(indexS2))
return false;
return isStringReversedRec(s1, s2, indexS1 - 1, indexS2 + 1);
}

Related

What is wrong with my method isReverse

Write a recursive method called isReverse("word1", "word2") that accepts two Strings as parameters and returns true if the two Strings contain
the same sequence of characters as each other but in opposite order, ignoring case, and returning false otherwise.
For example, the call of:
isReverse("Desserts", "Stressed")
would return true. [So eat desserts when you are stressed?]
Null, empty and one letter strings are also to return true (if both parameters are the same value).
This is homework and I am having trouble making this code work appropriately. It returns true no matter what I do.
public static boolean isReverse(String word1, String word2)
{
if(word1 == null || word2 == null)
{
if(word1!= null && word2 != null)
{
return false;
}
return false;
}
else if(word1.length() == word2.length())
{
String firstWord = word1.substring(0, word1.length());
String secondWord = word2.substring(word2.length()-1);
if (firstWord.equalsIgnoreCase(secondWord))
{
return isReverse(word1.substring(0, word1.length()), word2.substring(word2.length() - 1));
}
}
return true;
}
First, you have this set so that it will only return false if both words are null; If they are not null you're re-calling the method(in the event that the length is equal), which will return true.
private static boolean isReverse(String a, String b) {
// make sure the strings are not null
if(a == null || b == null) return false;
// If the lengths are not equal, the strings cannot be reversed.
if(a.length() != b.length()) {
return false;
}
// Convert string b to an array;
char[] bArray = b.toCharArray();
// Create an array to write bArray into in reverse.
char[] copy = new char[bArray.length];
// Iterate through bArray in reverse and write to copy[]
for(int i = bArray.length; i < 0; i--) {
copy[bArray.length - i] = bArray[i];
}
// Convert copy[] back into a string.
String check = String.valueOf(copy);
// See if they reversed string is equal to the original string.
if(check.equalsIgnoreCase(a)) {
return true;
} else {
return false;
}
}
You are saying
if (firstWord.equalsIgnoreCase(secondWord))
{
return isReverse(word1.substring(0, word1.length()), word2.substring(word2.length() - 1));
}
which is OK. But what if firstWord does not equal second word
It falls through and returns true.
You need to add an
else
return false;
I will also add that your null checking will not work.
if(word1!= null && word2 != null)
{
return false;
}
Is not useful because you are already in an if that only happens when word1 or word2 is null. So they can't be null and null here.
It would work if you made it
if(word1 == null && word2 == null)
{
return true;
}
Is this an exercise? Recursion doesn't seems to be the best option here. Anyway, you're just trimming one word, why? You must trim both words if you expect to compare each char in each recursive call. And you're not even passing the trimmed words as parameter to the recursive function!
The basic thing you're missing is a base case. When the recursion must return? In your case, you're reducing each string size at each step of recursion, so you must have a base case to check if the size is one.
Hope that this code clear your mind:
public static boolean isReverse(String word1, String word2) {
if (word1 == null || word2 == null) {
return false;
}
if (word1.length() == 1 && word2.length() == 1) {
//Used equals just for fast compare
return word1.equals(word2);
} else if (word1.length() == word2.length()) {
if (word1.charAt(0) == word2.charAt(word2.length() - 1)) {
String firstWord = word1.substring(1, word1.length());
String secondWord = word2.substring(0, word2.length() - 1);
System.out.printf("Trimmed %s, %s to %s, %s\n", word1, word2, firstWord, secondWord);
return isReverse(firstWord, secondWord);
} else {
//Characters didn't matched
return false;
}
} else {
//Lenght doesn't match
return false;
}
}
First I have reversed one of the string(i took word1) using recursion.then compared to second string if both strings are equal result set to true.
public static boolean isReverse(String word1, String word2)
{
boolean result = false;
//check null to avoid null pointer exception
if(word1 == null | word2 == null){
result = false;
}else if(word1.length() == word2.length()){
word1 = reverseString(word1);
if(word1.equalsIgnoreCase(word2)){
result = true;
}
}
return result;
}
static String reverse = "";
public static String reverseString(String str){
if(str.length() == 1){
reverse+=str;
} else {
reverse += str.charAt(str.length()-1)
+reverseString(str.substring(0,str.length()-1));
}
return reverse;
}

Check if a string A can be created from string B chars (is abbcccd derived from abcd )?

I'm trying to write a recursive method that checks if all string A unique chars are a subset of string B.
Examples:
String A = "a"
isTrans(A,"a") == true
isTrans(A,"aa") == true
isTrans(A,"aaa") == true
isTrans(A,"aab") == false
String A = "acd"
isTrans(A,"addbc") == false
isTrans(A,"aacdd") == true
isTrans(A,"acccd") == true
isTrans(A,"aaaccdd") == true
That's my code:
public static boolean isTrans(String s,String t)
{
boolean isT=false;
if(t.length()>1)
{
if(s.substring(0,1).equals(t.substring(0,1))&&(t.substring(0,1)!=t.substring(1,2)))
{
return isTrans(s.substring(1,s.length()),t.substring(1,t.length()));
}
if((s.substring(0,1)).equals(t.substring(0,1))&&((t.substring(0,1)).equals(t.substring(1,2))))
{
return isTrans(s,t.substring(1,t.length()));
}
}
else
{
isT =(s.substring(0,1).equals(t.substring(0,1)))?true:false;
}
return isT;
}
You need to correct
t.substring(0,1)!=t.substring(1,2)
The == and != operators don't work on strings the same way they do on primitive types.
You could replace it with something like
!t.substring(0,1).equals(t.substring(1,2))
But a better approach would be to check characters directly.
Try the below snippet i modified to replace substring with charAt.
public static boolean isTrans(String s, String t) {
System.out.println(s + " - " + t);
boolean isT = false;
if (t.length() > 1) {
if (s.charAt(0) == t.charAt(0) && (t.charAt(0) != t.charAt(1))) {
return isTrans(s.substring(1, s.length()), t.substring(1, t.length()));
}
if (s.charAt(0) == t.charAt(0) && t.charAt(0) == t.charAt(1)) {
return isTrans(s, t.substring(1, t.length()));
}
} else {
isT = (s.charAt(0) == t.charAt(0)) ? true : false;
}
return isT;
}
You can achieve this with the help of regular expressions.
Try this:
String s = "a";
String t1 = "aa";
String t2 = "aab";
System.out.println("t1->" + t1.replaceAll("(.+?)\\1+", "$1").equals(s));
System.out.println("t2->" + t2.replaceAll("(.+?)\\1+", "$1").equals(s));
s = "acd";
t1="addc";
t2 = "aaaccddd";
System.out.println("t1->" + t1.replaceAll("(.+?)\\1+", "$1").equals(s));
System.out.println("t2->" + t2.replaceAll("(.+?)\\1+", "$1").equals(s));
Hope it helps.

Recursive isSubtring method java

I have the following question:
Write a recursive static method isSubstring with the following signature -
public static boolean isSubstring(String s1,String s2)
gets two strings - s1, s2 and returns true if s2 is a substring of s1.
the method should be recursive without using iterations at all. also any other method you write (if you write).
the correct answer does not change the method type signature/annotation (not even by overloading).
you can only use the following methods in your solution:
public char charAt(int i)
public int length()
public String substring(int i)
that's what I have so far, I know it doesn't work IE isSubstring("hello","ho") will return true. any idea what could be done?
public static boolean isSubstring(String s1, String s2) {
if (s2.length() == 0)
return true;
if ((s1.length() == 0) || (s1.length() < s2.length()))
return false;
if (s1.charAt(0) != s2.charAt(0))
return isSubstring(s1.substring(1), s2);
else
return isSubstring(s1.substring(1), s2.substring(1));
}
I think this should do it.
It uses an auxiliary method. When you see the first match, it will call the auxiliary method and verify if the substring matches from that point. If it doesn't, it tries the same with the next match.
public static boolean isSubstring(final String s1, final String s2) {
if (s2.length() == 0) {
return true;
}
if ((s1.length() == 0) || (s1.length() < s2.length())) {
return false;
}
if (s1.charAt(0) != s2.charAt(0)) {
return isSubstring(s1.substring(1), s2);
}
if (!isSubstringAux(s1.substring(1), s2.substring(1))) {
return isSubstring(s1.substring(1), s2);
}
return true;
}
public static boolean isSubstringAux(final String s1, final String s2) {
if (s2.length() == 0) {
return true;
}
if (s1.charAt(0) == s2.charAt(0)) {
return isSubstringAux(s1.substring(1), s2.substring(1));
}
return false;
}
Your solution is almost good but you have to somehow remember that you made a replacement. I propose the following solution (using a helper function with a different prototype, which fits the requirements of the problem) :
public static boolean sub(final String s1, final String s2, final boolean hasReplaced) {
if (s2.length() == 0) {
return true;
}
if ((s1.length() == 0) || (s1.length() < s2.length())) {
return false;
}
if (s1.charAt(0) != s2.charAt(0)) {
if (hasReplaced) {
return false;
}
return sub(s1.substring(1), s2, hasReplaced);
}
return sub(s1.substring(1), s2.substring(1), true);
}
public static boolean isSubstring(final String s1, final String s2) {
return sub(s1, s2, false);
}
public static boolean isSubstring(String s1, String s2) {
return s2.length() == 0
|| ( s1.length() >= s2.length()
&& ( matchStartOfString( s1, s2 )
|| isSubstring( s1.substring(1), s2 )
)
);
}
private static boolean matchStartOfString( final String s1, final String s2 )
{
return s2.length() == 0
|| ( s1.length() >= s2.length()
&& s1.charAt( 0 ) == s2.charAt( 0 )
&& matchStartOfString( s1.substring(1), s2.substring(1) )
);
}
public static boolean isSubstring(String s1, String s2){
if (s2.length == 0) return true;
if (s1.length < s2.length) return false;
if (s1.charAt(0) == s2.charAt(0))
return isPrefixString(s1.substring(1, s2.length), s2.substring(1, s2.length))
|| isSubstring(s1.substring(1, s1.length), s2);
return isSubstring(s1.substring(1, s1.length), s2);
}
private static boolean isPrefixString(String s1, String s2){
if (s2.length == 0) return true;
if (s1.charAt(0) != s2.charAt(0)) return false;
return isPrefixString(s1.substring(1, s1.length), s2.substring(1, s2.length));
}
Basic algorithm:
isSubstring function:
Base case 1: If s2 is empty (either because it's empty or because it's been exhausted) then return vacuous truth (every string contains the empty string).
Base case 2: If s1 is shorter than s2, then s1 can't possibly contain s2, so return tautologic false.
Recursive case 1: If s1 contains s2, then some substring of s1 starts with the same letter as s2 starts with. Therefore, if s1 does not start with the same letter as s2, find some other point in the string to use as the start point. By "some other", this algorithm just iterates linearly through the string.
Recursive case 2: If s1 and s2 start with the same string, test whether s2 is a prefix string of s1 (i.e. if s1 starts with s2) recursively. If s2 is not a prefix string of s1, then try another start point. Otherwise, s2 is a prefix of s1 and hence s1 contains s2.
Note that the code has recursive cases 1 and 2 backwards from how I've written it here.
isPrefixString function:
Base case 1: If s2 is empty, then return (vacuous) truth.
Base case 2: If s1 and s2 do not start with the same letter, then s2 cannot possibly be a prefix of s1, so return false.
Recursive case: If s1 and s2 start with the same character, check if the next character is the same as well.
Recursion should be thought of as two parts.
1) A base case. This is trivial case that can easily be determined.
What you have so far is a good start to a base case.
1) Is the string less then 3? Then return false.
2) Does the string start with "bab" then return true.
2) A recursive case.
This splits the problem up into a tinier problems, and if you split them up enough hopefully you have a base case.
Here is a good example of a simple recursion.
public static boolean substringRec(String str, String str2) {
if (str.length() < str2.length()) return false;
if (str.length() == str2.length())
{
if (equals(str, str2))
return true;
return false;
}
else
return substringRec(str.substring(1), str2);
}
public static boolean equals(String str1, String str2)
{
if (str1.charAt(0) == str2.charAt(0))
{
if (str1.length() == 1)
return true;
return equals(str1.substring(1), str2.substring(1));
}
return false;
}
This uses simple base cases and as a recursive case checks the string from index one on. This reduces our string only by one charter, but is enough to solve the problem.I had to implement a .equals since apparently you can't use that, you can do that in a similar way.
This means we end up with a stack level of the length of the string.
Can we do better? A little, by breaking the problem in half we only need a stack level of ln(n) where n is the length of string. This is not a big deal for most lengths, but if you were searching a string with a length of one million it maybe significant. With the first version our stack would be about a 1,000,000 deep! But with this binary version we only need to go about 14 levels deep.
This comes at a cost though, our solution because more involved and will break some of the rules you have on your assignment, but I think it's interesting to think about.
Our base cases
1) If the string is less then the length of the search string, return false.
2) If the string is length of the search string, if they are equal return true, else return false.
3) If the string appears over the mid point of the string return true.
If none of these are true,we break the string into two parts and recursively check over that string.
Here is an example of that algorithm, although it hasn't been fully tested for that I'm pretty sure it will be okay.
public static boolean substringRec2(String str, String searchString) {
// Base cases
if (str.length() < searchString.length())
return false;
if (str.length() == searchString.length())
{
if (str.equals(searchString))
{
return true;
}
return false;
}
int halfWay = str.length()/2;
// Now check for the search string over the "break"
for (int i = 0; i < searchString.length(); i++)
{
int startIndex = halfWay - 1 - i;
int endIndex = startIndex + 3;
if (startIndex >= 0)
{
String substring = str.substring(startIndex, endIndex);
if (substring.equals(searchString))
{
return true;
}
}
}
// Recursive Cases
// We did find the search string over the break,so break the string into two equal(ish) pieces and check those
if(substringRec2(str.substring(0,halfWay -1), searchString))
return true;
if(substringRec2(str.substring(halfWay, str.length()), searchString))
return true;
return false;
}
Note - taken from one of my previous answers and modified - https://stackoverflow.com/a/21594554/3096507

Check if given string is interleaved of two other string

I wrote the code for checking if S3 is a interleaving of S1 and S2 string.
But it fails for simple strings like "AB" , "CD" -> "ACBD"
Am I missing something ?
class InterleavedString {
// error
public static boolean isInterleaved (String A, String B, String C)
{
// Iterate through all characters of C.
int a = 0, b = 0, c = 0;
while (C != null)
{
// Match first character of C with first character of A,
// If matches them move A to next
if (A.charAt(a) == C.charAt(c))
a++;
// Else Match first character of C with first character of B,
// If matches them move B to next
else if (B.charAt(b) == C.charAt(c))
b++;
// If doesn't match with either A or B, then return false
else
return false;
// Move C to next for next iteration
c++;
}
// If A or B still have some characters, then length of C is smaller
// than sum of lengths of A and B, so return false
if (A != null || B != null)
return false;
return true;
}
public static void main(String [] args) {
String A = "AB", B = "CD", C = "ACBD";
System.out.println(isInterleaved(A, B, C));
}
}
ERROR :
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 2 at java.lang.String.charAt(Unknown
Source) at
strings.InterleavedString.isInterleaved(InterleavedString.java:14) at
strings.InterleavedString.main(InterleavedString.java:40)
EDITED :
while (c != C.length())
.....
.....
if (a != A.length() || b != B.length())
The condition of your while statement is wrong. You are never changing your value of C. Instead of while (C != null) you should use while c != C.length() or something similar.
The same problem is with your A != null and B != null statements because charAt does not remove any characters!
In addition you need to check the bounds of your Strings in your if clauses:
if (a < A.length() && A.charAt(a) == C.charAt(c))
Also if you are aiming for efficiency you should add this check at the beginning of your method and in turn remove the last if statement:
if (A.length() + B.length() != C.length())
return false;
This is wrong .. Try with "XXY", "XXZ", "XXZXXY" .. The output will be false
boolean interleaving(String s1, String s2, String s3){
char a[] = s1.toCharArray();
char b[] = s2.toCharArray();
char c[] = s3.toCharArray();
if(a.length+b.length!=c.length){
return false;
}
int i=0,j=0,k=0;
while(k<=c.length-1){
if(i<a.length && c[k]==a[i]){
i++;
}else if(j<b.length && c[k]==b[j]){
j++;
}else{
return false;
}
k++;
}
return true;
}

Improving my Java method containsSubstring(s1, s2) which finds if s2 is a substring of s1

I am a college student that was recently interviewed for an internship position. One of the things asked of me was to write a method that took two Strings as input and returned true if the second argument was a substring of the first. The answer I turned in wasn't satisfactory to me, so while I was driving home I thought of the following solution:
// containsSubstring(s1,s2) returns true if the string s2 is contained within s1
public static boolean containsSubstring(String s1, String s2) {
if(s2.length()==0 && s1!=null)
return true;
for(int i=s2.length()-1;i<=s1.length()-1;i++) {
if(s2.charAt(s2.length()-1) == (s1.charAt(i))) {
int k=i;
for(int j=s2.length(); j>0;j--) {
if(s1.charAt(k) != s2.charAt(j-1))
j=-1; // exits loop.
else if (j == 1)
return true;
else
k--;
}
}
}
return false;
}
This code basically checks to see if the last character of s2 is equal to the current index of s1 and if so, loops backward through both to see if they match exactly.
Two things I like about this solution are that if s2.length() > s1.length(), the loop won't execute and the method will just return false and also that it doesn't have to check every character in s1 to find the answer.
Are there any improvements I could make in terms of readability, methodology, better programming practices, etc.?
I suggest to look at how String.contains(CharSequence src) src is implemented, supposed to be good
I would do it this way:
public static boolean containsSubstring(String s1, String s2) {
if(s2.length()==0 && s1!=null)
return true;
for(int i=0; i < s1.length() - s2.length() + 1; i++) {
int k = 0;
while (k < s2.length() && s1.charAt(k+i) == s2.charAt(k++));
if (k == s2.length() && s1.charAt(k+i-1) == s2.charAt(k-1)) return true;
}
return false;
}
You can test it here: http://ideone.com/PwEaf4
I would prefer to do it using following way.
private boolean isSubString(String s1, String s2) {
if(s1==null && s2==null) return true;
else if (s1== null) return false;
else if (s2 == null) return true;
char[] a1 = s1.toCharArray();
char[] a2 = s2.toCharArray();
int l1 = s1.length();
int l2 = s2.length();
int i=0;
while(i<l1) {
int j=0;
while(j<l2 && i<l1 && a1[i]==a2[j]){
i++;
j++;
if(j==l2) {
return true;
}
}
i++;
}
return false;
}

Categories