I needed to Write a recursive method to compare two Strings using alphabetical order without using compareTo.
string1 comes before string2 returns an integer less than 0
string1 == (or indistinguishable from) string2 returns 0
string1 comes after string2 returns an integer greater than 0
I have written a method that works just fine, the problem is that if I compare two similar string or a string to itself it returns 1 instead of 0.
Any idea how can I optimize my method so it is not too long and does not fail to compare two identical strings?
I think part of my problem is because I declared my variable static, but not sure how I should work it out to declare them inside the method.
Code:
public class test{
public static String s1 = "alpha";
public static String s2 = "delta";
public static String s3 = "omega";
public static String s4 = "alpha";
public static int result;
public static void main (String[]args){
System.out.println(recursiveCompare(s1,s2)); // -1 good
System.out.println(recursiveCompare(s3,s1)); // 1 good
System.out.println(recursiveCompare(s4,s1)); // 1 FAIL!!! should be 0
System.out.println(recursiveCompare(s2,s3)); // -1 good
System.out.println(recursiveCompare(s1,s1)); // -1 FAIL!!! should be 0
}
public static int recursiveCompare(String s1, String S2){
if (s1.length() ==0 || s2.length()==0){
if ((s1.length() ==0 && s2.length()==0)){result = 0;}
else if ((s1.length() !=0 || s2.length()==0)){result = 1;}
else if ((s1.length() ==0 || s2.length()!=0)){result = -1;}
}
else
{
recursiveCompareHelper(s1, s2,0);
}
return result;
}
public static int recursiveCompareHelper(String s1,String s2, int index){
try{
if (s1.regionMatches(true,index,s2,index,1)){
result = recursiveCompareHelper(s1,s2,(index+1));}
else {
if (s1.charAt(index) > s2.charAt(index)){
result =1;
}
else if (s1.charAt(index) < s2.charAt(index)){
result =-1;
}
else if (s1.charAt(index) == s2.charAt(index)){
result = recursiveCompareHelper(s1,s2,(index+1));
}
}
} catch (StringIndexOutOfBoundsException e){
if (s1.charAt(index)==0 && s2.charAt(index)== 0){result = 0;}
else if (s1.charAt(index)==0 && s2.charAt(index)!= 0){result = 1;}
else if (s1.charAt(index)!=0 && s2.charAt(index)== 0){result =-1;}
}
return result;
}
}
first of all, notice you pass S2 as a parameter to recursiveCompare, not s2,
so actually you compare everything with "delta" because s2 is a static variable.
second of all, when comparing strings, as soon as you find a difference you can return an answer, its wrong just to change the value of result because it can be changed again later and return a wrong answer.
this is my solution, inside each recursive call I compare between the first letters and
if they're equal, I call the function recursively without the first letters of the strings
public class test {
public static String s1 = "alpha";
public static String s2 = "delta";
public static String s3 = "omega";
public static String s4 = "alpha";
public static void main(String[] args) {
System.out.println(recursiveCompare(s1, s2)); // -1 good
System.out.println(recursiveCompare(s3, s1)); // 1 good
System.out.println(recursiveCompare(s4, s1)); // 1 FAIL!!! should be 0
System.out.println(recursiveCompare(s2, s3)); // -1 good
System.out.println(recursiveCompare(s1, s1)); // -1 FAIL!!! should be 0
}
public static int recursiveCompare(String s1, String s2) {
if (s1.length() == 0 || s2.length() == 0) {
if ((s1.length() == 0 && s2.length() == 0)) {
return 0;
} else if (s1.length() != 0) {
return 1;
} else {
return -1;
}
}
if (s1.charAt(0) < s2.charAt(0)) {
return -1;
} else if (s1.charAt(0) > s2.charAt(0)) {
return 1;
} else if (s1.charAt(0) == s2.charAt(0)) {
return 0;
} else {
return recursiveCompare(s1.substring(1), s2.substring(1));
}
}
}
output:
-1
1
0
-1
0
You do not need to use the .langth() method. To compare strings, you need to use .equals()
public static int recursiveCompare(String s1, String s2){
if (s1.equals(s2)) {
return 0;
}
else
{
recursiveCompareHelper(s1, s2,0);
}
return result;
}
And in recursiveCompare(String s1, String S2) you hava S2 insted of s2.
Main mistake that you have done in your program is in function recursiveCompare you have taken argument as S2 and in a function using variable s2 which is declared as static variable so your function is failing to give correct result. Remember java is case sensitive language and in that case S2 is not same as s2.
below is the program which i have modified use that for your understanding.
public class Test{
/* public static String s1 = "alpha";
public static String s2 = "delta";
public static String s3 = "omega";
public static String s4 = "alpha";*/
public static int result;
public static void main (String[]args){
String s1 = "alpha";
String s2 = "delta";
String s3 = "omega";
String s4 = "alpha";
System.out.println(recursiveCompare(s1,s2)); // -1 good
System.out.println(recursiveCompare(s3,s1)); // 1 good
System.out.println(recursiveCompare(s4,s1)); // 1 FAIL!!! should be 0
System.out.println(recursiveCompare(s2,s3)); // -1 good
System.out.println(recursiveCompare(s1,s1)); // -1 FAIL!!! should be 0
}
public static int recursiveCompare(String s1, String S2){
if (s1.length() ==0 || S2.length()==0){ // here you have to use S2 and not s1
if ((s1.length() ==0 && S2.length()==0)){result = 0;}
else if ((s1.length() !=0 || S2.length()==0)){result = 1;}
else if ((s1.length() ==0 || S2.length()!=0)){result = -1;}
}
else
{
recursiveCompareHelper(s1, S2,0);
}
return result;
}
public static int recursiveCompareHelper(String s1,String s2, int index){
// System.out.println("String are" + s1+" "+ s2 + " index is "+ index);
if(index<s1.length()) {
// System.out.println("Characters at index : "+ s1.charAt(index)+ " "+ s2.charAt(index));
if (s1.charAt(index) > s2.charAt(index)){
//System.out.println("In the if condition");
result= 1;
}
else if (s1.charAt(index) < s2.charAt(index)){
//System.out.println("In the else if condition");
result =-1;
}
else if (s1.charAt(index) == s2.charAt(index)){
//System.out.println("Character at "+index);
result = recursiveCompareHelper(s1,s2,(index+1));
}
}
else return 0;
return result;
}
}
Related
I need to find the index of the first distinct character between two strings using a recursive method.
Examples with expected outputs:
rFirstDistinctPlace("Little parcels", "Little pretzels") -> 8
rFirstDistinctPlace("Gold shadow", "gold shadow") -> 0
rFirstDistinctPlace("gold", "golda") -> 4
rFirstDistinctPlace("gold","gold") -> -1
Note:
I can't use the .equals() function
The thing I'm struggling with is that I need to return -1 if the strings are equal, otherwise it works fine.
Here's my code:
public static int rFirstDistinctPlace (String s1, String s2) {
if (smallestString(s1,s2).length()==0){
return 0;
}
if(s1.charAt(0)!=s2.charAt(0))
return rFirstDistinctPlace(s1.substring(0,0),s2.substring(0,0));
return 1+rFirstDistinctPlace(s1.substring(1),s2.substring(1));
}
This is the helper method smallestString:
public static String smallestString (String s1, String s2){
if(s1.length()>s2.length()){
return s2;
}
else if (s2.length()>s1.length()){
return s1;
}
else
return s1;
}
Thank you!
Recursive Solution:
If the two strings are empty, this means they are equal, return -1
Else if one of them is empty or the first characters don't match, return 0
Else recur with the substrings, if the result is -1, return it, else return it plus 1
public static void main(String[] args) {
System.out.println(rFirstDistinctPlace("Little parcels", "Little pretzels")); //8
System.out.println(rFirstDistinctPlace("Gold shadow", "gold shadow")); //0
System.out.println(rFirstDistinctPlace("gold", "golda")); //4
System.out.println(rFirstDistinctPlace("gold","gold")); //-1
}
public static int rFirstDistinctPlace (String s1, String s2) {
if(s1.isEmpty() && s2.isEmpty()) return -1;
else if (s1.isEmpty() || s2.isEmpty() || s1.charAt(0) != s2.charAt(0)) return 0;
int index = rFirstDistinctPlace(s1.substring(1), s2.substring(1));
return index == -1 ? index : 1 + index;
}
Iterative Solution:
Iterate over the two strings using a for-loop until it reaches the end of one of them
If the characters of the two strings at the current index are different, return i
At the end, if the two strings have different lengths, return i, else return -1
public static int rFirstDistinctPlace (String s1, String s2) {
int i = 0;
for(i = 0; i < s1.length() && i < s2.length(); i++) {
if(s1.charAt(i) != s2.charAt(i)) {
return i;
}
}
return s1.length() != s2.length() ? i : -1;
}
It's not so complex.
Return -1 if the strings are equal.
Return 0 if the length of one of the strings is 0 or if their first characters do not match.
Otherwise, return 1 + rFirstDistinctPlace(s1.substring(1), s2.substring(1)).
Demo:
class Main {
public static void main(String[] args) {
System.out.println(rFirstDistinctPlace("Little parcels", "Little pretzels")); // 8
System.out.println(rFirstDistinctPlace("Gold shadow", "gold shadow"));// 0
System.out.println(rFirstDistinctPlace("gold", "golda"));// 4
System.out.println(rFirstDistinctPlace("gold", "gold"));// -1
}
public static int rFirstDistinctPlace(String s1, String s2) {
if (Objects.equals(s1, s2))
return -1;
if (s1.length() == 0 || s2.length() == 0 || s1.charAt(0) != s2.charAt(0))
return 0;
return 1 + rFirstDistinctPlace(s1.substring(1), s2.substring(1));
}
}
Output:
8
0
4
-1
I am having trouble getting s1 and s2 to compare properly. If I add multiple strings to my ArrayList<String>, it seems to stop after running once. So I am missing a recursive method to help my findMinimum method I think.
I need to provide code to create a Tester class but I am just trying to create a working program at this point. Any help is appreciated. I do need to use recursion for this assignment otherwise I would use a different route.
public class BigComp {
// public static String s1;
// public static String s2;
public static void main(String[] args) {
// String s1 = "badd"; //, "job", "any";
// String s2 = "hat";//,"zFat","got";
ArrayList<String> stringArray = new ArrayList<String>();
stringArray.add("acc");
stringArray.add("Dbc");
stringArray.add("bac");
// compareTo(s1,s2);
// findMinimum(stringArray);
System.out.println(findMinimum(stringArray));
}
public static int compareTo(String s1, String s2) {
if(s1.charAt(0) < s2.charAt(0)) {
return -1; // String s1 is alphabetically before s2
}
if(s1.charAt(0) > s2.charAt(0)) {
return 1; // String s1 is alphabetically after s2
}
if(s1.charAt(0) == s2.charAt(0)) {
if(s1.length()== 1 && s2.length() ==1) {
return 0; // both strings being compared are identical
}
if(s1.length() == 1 && s2.length() > 1) {
return -1; // s1 is before s2
}
if(s1.length() > 1 && s2.length()== 1) {
return 1; // s2 is before s1
}
}
return compareTo(s1.substring(1), s2.substring(1));
} // end of compareTo method
public static String findMinimum(ArrayList<String> stringArray) {
String s1 = stringArray.get(0);
int max = stringArray.size()-1;
String s2 = stringArray.get(max);
int temp = compareTo(s1, s2);
// if(stringArray.size() == 1) {
// return stringArray.get(0);
// }
if(temp == 0) {
stringArray.remove(max);
return findMinimum(stringArray);
}
else if(temp == 1) {
stringArray.remove(s1);
return findMinimum(stringArray);
}
else {
stringArray.remove(s2);
return findMinimum(stringArray);
}
} // end findMinimum method
} // end of BigComp class
Your code will get an java.lang.IndexOutOfBoundsException, because method findMinimum has no case for the stop of recursion. You can add this line at the begin of the method findMinimum:
if (stringArray.size() == 1) return stringArray.get(0);
.charAt returns char type, that means they will be compared by ASCII code. Maybe you need to use compareToIgnoreCase:
public static int compareTo(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
I am stuck at solving this problem. Below is what I came up with most:
Question: Write the boolean method public static boolean isSubstring(String x, String y) that takes two Strings x and y as arguments and returns true if an only if String x is a substring of String y. String x is a substring of String y if and only if all characters in x appear consecutively in y. For this problem, the only String methods you may use are length( ) and charAt( ). If you use any other String methods, you will receive no credit for this problem.
import java.util.Scanner;
public class question {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter String 1:");
String String1 = input.nextLine();
System.out.print("Enter String 2:");
String String2 = input.nextLine();
if(isSubstring(String1,String2)){
System.out.println("True");
} else {
System.out.println("False");
}
}
public static boolean isSubstring(String x, String y) {
int count = 0, xIndex = 0, yIndex = 0;
boolean sub = false;
while(!sub && yIndex < y.length()){
if(y.charAt(yIndex) == x.charAt(yIndex)){
xIndex++;
count++;
} else {
if(count == x.length()){
sub = true;
}
}
yIndex++;
}
return sub;
}
}
This checks if s2 is a substring of s1.
public static boolean isSubstring(String s1, String s2){
if(s1.length()<s2.length()) return false;
if(s1.length()==s2.length()) return s1.equals(s2);
for(int i=0;i<=s1.length()-s2.length();i++){
if(s1.charAt(i)==s2.charAt(0)){
int matchLength=1;
for(int j=1;j<s2.length();j++){
if(s1.charAt(i+j)!=s2.charAt(j)){
break;
}
matchLength++;
}
if(matchLength==s2.length()) return true;
}
}
return false;
}
You're not guarding xIndex for overflow. Guess if substring y is placed at end of x it fails. Also mind the case where x is of smaller length than x, could just return false then as optimization if you keep lengths first in local vars at start of method
public class Task_1_9 {
public static boolean isSubstring(String s1, String s2){
if (s1.length() != s2.length()) return false;
int count = 0;
int i = 0;
int j = 0;
String s3 = s2 + s2;
while (j < s3.length() && count < s1.length()){
if (s1.charAt(i) == s3.charAt(j)){
count++;
i++;
} else {
count = 0;
}
j++;
}
return count == s1.length() ? true : false;
}
public static void main(String[] args) {
System.out.println(isSubstring("waterbottle","erbottlewat"));
}
}
public int indexOf(String s1,String s2){
if(s1.length()<s2.length())
return -1;
else if(s1.substring(s1.length()-s2.length()).equals(s2))
return s1.length()-s2.length();
else
return indexOf(s1.substring(0,s1.length()-1),s2);
}
I wrote this method to get index of the second string in the first one
but it has a bug it cant effectively return first occurrence of the second string this is because I am using logic to find the second string from backwards and I could not think of any other logic. Any suggestions would be appreciated.
example of a failure case: firstString "BarackObama" second string "a"
As you noted, you are doing it backwards. Instead, you should go forward:
public static int indexOf(String s1, String s2){
if(s1.length()<s2.length()) {
return -1;
}
else if(s1.substring(0, s2.length()).equals(s2)) {
return 0;
}
else {
int i = indexOf(s1.substring(1, s1.length()), s2);
if (i == -1) {
return i;
} else {
return 1 + i;
}
}
}
Example:
String s1 = "BarackObama";
String s2 = "rac";
indexOf(s1, s2);
It would run like this:
indexOf("BarackObama", "rac"):
"BarackObama".substring(0, 3).equals("rac") -> false
return 1 + indexOf("BarackObama".substring(1, 11), "rac")
indexOf("arackObama", "rac"):
"arackObama".substring(0, 3).equals("rac") -> false
return 1 + indexOf("arackObama".substring(1, 10), "rac")
indexOf("rackObama", "rac"):
"rackObama".substring(0, 3).equals("rac") -> true
return 0;
return 0 + 1 + 1 = 2
I think the way you are using subString(int startIndex), it would give you characters from the end. If you pass only on parameter to the subString method, it acts as the start index for the subString it returns. So in case your example, you would get the "a" at the end of "BarackObama". You can try to use substring(int beginIndex, int endIndex).
Here it is.
private int indexOf(String s1,String s2){
int index=0;
if( s1 ==null || s2 ==null){
return -1;
}else if(s1.length()<s2.length()){
return -1;
}else{
index=s1.lastIndexOf(s2);
s1=s1.substring(0,index);
if(!s1.contains(s2)){
return index;
}else{
return indexOf(s1,s2);
}
}
}
public int indexOf(String s1, String s2){
if (s1.length() < s2.length()){
return -1;
} else {
int n = 0;
int index = findIndex(s1, s2, n);
return index;
}
}
private int findIndex(String s1, String s2, int n){
if (s1.substring(n, (n + s2.length())).equals(s2)){
return n;
} else if ((n < s1.length() - s2.length())){
return findIndex(s1, s2, (n + 1));
} else{
return -1;
}
}
I need to write a recursive method called indexOf that accepts two Strings as parameters and that returns the starting index of the first occurrence of the second String inside the first String (or -1 if not found). I have to solve this problem using recursion.
These are some example results:
indexOf("Barack Obama", "Bar") 0
indexOf("Barack Obama", "ck") 4
indexOf("Barack Obama", "a") 1
indexOf("Barack Obama", "McCain") -1
indexOf("Barack Obama", "BAR") -1
This is my solution but it gives me 6 for indexOf("Barack Obama", "McCain")instead of -1.
public static int indexOf(String s1, String s2) {
if(s1.equals(s2))
return 0;
else
return indexOfHelper(s1, s2, 0);
}
private static int indexOfHelper(String s1, String s2, int ctr) {
if(s2.length() > s1.length())
return -1;
if(s2.length() == 0 || s1.length() == 0) //base case
return ctr;
else //recursive case
if(s1.charAt(0) == s2.charAt(0)){ //if there is a matching character
if(s1.substring(0, s2.length()).equals(s2))
return ctr; //if there is a matching character and the rest of the strings match as well
else
return -1; //if there is a matching character but the rest of the strings don't match
}
else
return 1 + indexOfHelper(s1.substring(1), s2, ctr);
}
I must say that recursive step was quite tricky. It passes all test cases. I hope following helps. Java and C++ code here
JAVA
int indexOf (String s1, String s2) {
if (s1.length() == 0 && s2.length() == 0) {
return 0;
} else if (s1.length() == 0) {
return -1;
} else if (s2.length() == 0) {
return 0;
} else if (s2.length()>s1.length()) {
return -1;
}
else if (s1.charAt(0) == s2.charAt(0)) {
int subIndex = indexOf(s1.substring(1),s2.substring(1));
return subIndex == -1 ? -1: subIndex;
} else {
int subIndex = indexOf(s1.substring(1),s2);
return subIndex == -1 ? -1: subIndex+1;
}
}
C++ code here
int indexOf (string s1, string s2) {
if (s1 == "" && s2 == "") {
return 0;
} else if (s1 == "") {
return -1;
} else if (s2=="") {
return 0;
} else if (s2.size()>s1.size()) {
return -1;
}
else if (s1 [0] == s2[0]) {
int subIndex = indexOf(s1.substr(1,s1.length()),s2.substr(1,s2.length()));
return subIndex == -1 ? -1: subIndex;
} else {
int subIndex = indexOf(s1.substr(1,s1.length()),s2);
return subIndex == -1 ? -1: subIndex+1;
}
}
Here is my solution
public static void main(String[] args) {
System.out.println(indexOf("Ninja!", "i"));
System.out.println(indexOf("ninja2", "ja2"));
System.out.println(indexOf("ninja2", "hae"));
}
public static int indexOf(String s, String contains) {
if (contains.length() > s.length()) {
return -1;
}
return indexOf(s, contains, 0);
}
private static int indexOf(String s, String contains, int index) {
if ((s.length() - contains.length()) < index) {
return -1;
}
if (s.substring(index, index + contains.length()).equals(contains)) {
return index;
} else {
return indexOf(s, contains, index + 1);
}
}