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);
}
}
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 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;
}
}
I am trying to write code for the following string operations:
1) to reverse a string.
This is what I have:
String rev = "";
String reverse(String s){
if(s.length() == 1){
return s;
}
else {
rev += s.charAt(s.length()-1)
+reverse(s.substring(0,s.length()-1));
return rev;
}
}
2) If two strings are equal to each other.
int compareString(char a, char b, int n){
if (n == 0 || a == 0 || a != b){
return a - b;
}
else {
return(compareString(a+1, b+1, n-1));
}
}
3) if a string is a palindrome (for example, "eye" or "racecar") - reads the same forwards and backwards.
boolean checkPalindrome (String s){
if(s.length() == 0 || s.length() == 1){
return true;
}
if(s.charAt(0) == s.charAt(s.length()-1)){
return checkPalindrome (s.substring(1, s.length()-1));
}
return false;
}
I am unclear on 2. As an exercise in recursive thinking, I would prefer only recursion techniques and corrections for the above. Thank you.
If two strings are equal to each other.
When comparing two strings, you have to pass in the strings.
public static boolean isEquals(String a, String b) {
if (a.length() != b.length()) return false;
return isEquals(a, b, 0);
}
private static boolean isEquals(String a, String b, int index) {
if (index >= a.length()) return true;
if (a.charAt(index) != b.charAt(index)) return false;
return isEquals(a, b, index + 1);
}
or if performance doesn't matter
public static boolean isEquals(String a, String b) {
if (a.length() == 0)
return b.length() == 0;
if (b.length() == 0)
return false;
return a.charAt(0) == b.charAt(0) &&
isEquals(a.subString(1), b.subString(1));
}
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 am doing a problem from codingbat and I am stuck at this problem. The question asks me to find all the 'hi' in the string but ignore the 'hi' which have 'x' just before them. In other words, don't count 'xhi' but only 'hi'.
Every input works fine in my code except for when the input is "xxxx".
My code is as follows:
public int countHi2(String str) {
String s = "hi";
int count = 0;
if(str.length() < 2) {
return 0;
}
else if(str.charAt(0) == 'x' && str.substring(1,3).equals(s)) {
count+= countHi2(str.substring(3));
}
else if(str.substring(0,2).equals(s)){
count+= 1 + countHi2(str.substring(2));
}
else {
count+= countHi2(str.substring(1));
}
return count;
}
The problem is that it throws IndexOutOfBoundsException. The link to the question can be found here.
You could do as follows :
public static int countHi2(String str) {
if (str.startsWith("xhi")) {
return countHi2(str.substring(3));
} else if (str.startsWith("hi")) {
return countHi2(str.substring(2)) + 1;
} else if (str.length() > 0){
return countHi2(str.substring(1));
} else {
return 0;
}
}
(It does not handles null value, and it is really not optimized.)
You see an exception because substring throws IndexOutOfBoundsException if the beginIndex is negative, or endIndex is larger than the length of this String object, or beginIndex is larger than endIndex. You check for the length to be at least 2, and then do substring(1, 3), causing an exception.
You can avoid the problem with IndexOutOfBoundsException in substring by switching to startsWith API, which does not throw exceptions even when you compare your string to a longer one.
The problem is that if you have an 'x' at the end of your string (or at one of the last 2 positions), your substring will start at an index that is out of bounds (as your exception tells you). You could just check in that case, if str.substring(3) is feasible:
else if(str.charAt(0) == 'x' && str.substring(1,3).equals(s)) {
if (str.length() > 3) count+= countHi2(str.substring(3));
else return count;
}
line no 8 need to modify.
else if(str.length()>=3 && str.charAt(0) == 'x' && str.substring(1,3).equals(s))
{...}
Total code should be -
public int countHi2(String str) {
String s = "hi";
int count = 0;
if(str.length() < 2) {
return 0;
}
else if(str.length()>=3 && str.charAt(0) == 'x' && str.substring(1,3).equals(s)) {
count+= countHi2(str.substring(3));
}
else if(str.substring(0,2).equals(s)){
count+= 1 + countHi2(str.substring(2));
}
else {
count+= countHi2(str.substring(1));
}
return count;
}
Fixed one
public int countHi2(String str) {
String s = "hi";
int count = 0;
if(str.length() < 2) {
return 0;
}
else if(str.charAt(0) == 'x' && str.length() > 2 && str.substring(1,3).equals(s)) {
count+= countHi2(str.substring(3));
}
else if(str.substring(0,2).equals(s)){
count+= 1 + countHi2(str.substring(2));
}
else {
count+= countHi2(str.substring(1));
}
return count;
}
This code will perfome well for 'XXXX' and other combinations. But i haven't check for the all combinations.
public static int countHi2(String str) {
String s = "hi";
int count = 0;
if(str.length() < 2) {
return 0;
}
else if((str.length() >= 3) && (str.charAt(0) == 'x' && str.substring(1,3).equals(s))) {
count+= countHi2(str.substring(3));
}
else if(str.substring(0,2).equals(s)){
count+= 1 + countHi2(str.substring(2));
}
else {
count+= countHi2(str.substring(1));
}
return count;
}
you never get to this line
return count;
you are using if else all the time
when your input is 'xxxx' you keep getting to
count+= countHi2(str.substring(1));
when you have 2 letters remaining "xx" and you check the first condition, and you do str.substring(1,3) is when you get that error.
You should check that str.lenght() is not 2 in that case, for example:
public int countHi2(String str) {
String s = "hi";
int count = 0;
if(str.length() < 2) {
return 0;
}
else if(str.length()>2 && str.charAt(0) == 'x' && str.substring(1,3).equals(s)) {
count+= countHi2(str.substring(3));
}
else if(str.substring(0,2).equals(s)){
count+= 1 + countHi2(str.substring(2));
}
else {
count+= countHi2(str.substring(1));
}
return count;
}
you guys are complicating to much. here is a simple solution.
public int countHi2(String str) {
return (str.length() < 2)?0:
(str.substring(0,2).equals("xh"))?
countHi2(str.substring(2)):
(str.substring(0,2).equals("hi"))?
1 + countHi2(str.substring(1)):
countHi2(str.substring(1));
}
or if it looks too weird :
public int countHi2(String str) {
if(str.length() < 2)
return 0;
else if(str.substring(0,2).equals("xh"))
return countHi2(str.substring(2));
else (str.substring(0,2).equals("hi"))
return 1 + countHi2(str.substring(1));
else return countHi2(str.substring(1));
}
If you don't have to use recursion:
public int countHi(String test) {
if (test == null){
return 0;
}
test = test.replaceAll("xhi", "");
int n1 = test.length();
int n2 = test.replaceAll("hi", "").length();
return (n1-n2)/2;
}
Below is the code to fetch the count of 'hi' in a particular string.
public int countHi(String str) {
int count = 0;
int len = str.length();
if(len<2) {
return 0;
}
else {
if(str.substring(0,2).equals("hi")) {
return count+1+countHi(str.substring(2));
}
else {
return count+countHi(str.substring(1));
}
}
}