java recursion find the last index of a character in a string - java

Here is what I have for method lastIndexOf , ch is the character to match, and str is the source string.
public static int lastIndexOf(char ch, String str) {
// check for null string or empty string
if (str.length() == 0 || str == null) {
return -1;
}
int indexInRest = lastIndexOf(ch, str.substring(1));
char first = str.charAt(0);
// recursive call to find the last matching character
if (first == ch) {
return 1 + indexInRest; // this might not work properly
} else
return indexInRest;
}
If in my class' main method I call:
System.out.println(lastIndexOf('r', "recurse"));
System.out.println(lastIndexOf('p', "recurse"));
I got:
1
-1
The desired result is:
4
-1
Suggestion, please.

How about taking the functional approach..
public static int lastIndexOf(char ch, String str) {
if (str.charAt(str.length() - 1) == ch) { return str.length() -1; }
if (str.length() <= 1) { return -1; }
return lastIndexOf(ch, str.substring(0, str.length() - 1));
}

This must be homework because there would be no point to writing this method since String.lastIndexOf() exists in the API, and using recursion to do this going to be slow and use a lot of memory.
Here a hint. Right now your algorithm is chopping characters off the front ( substring(1) ) and comparing them. lastIndexOf() should start by removing characters at the back of the String looking for a match then quit when it finds one.

why not use String.lastIndexOf like this:
str.lastIndexOf(ch)

Use the String#lastIndexOf(int ch) implementation as a general guideline,
public int lastIndexOf(int ch) {
return lastIndexOf(ch, value.length - 1);
}
public int lastIndexOf(int ch, int fromIndex) {
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
int i = Math.min(fromIndex, value.length - 1);
for (; i >= 0; i--) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return lastIndexOfSupplementary(ch, fromIndex);
}
}
private int lastIndexOfSupplementary(int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[] value = this.value;
char hi = Character.highSurrogate(ch);
char lo = Character.lowSurrogate(ch);
int i = Math.min(fromIndex, value.length - 2);
for (; i >= 0; i--) {
if (value[i] == hi && value[i + 1] == lo) {
return i;
}
}
}
return -1;
}
And this,
lastIndexOf(ch, value.length - 1);
value is the target String as a character array.

First, you should change to:
if (str == null || str.length() == 0) {
Because a NPE could raise if str is null
Add a deep paramater to your code like this:
public static int lastIndexOf(char ch, String str, int deep) {
And increment its value every recursive call
int indexInRest = lastIndexOf(ch, str.substring(1), deep++);
then, in the return sentence, add deep to your returned value:
return 1 + indexInRest + deep; // this might not work properly
Call the function the first time with deep = 0, or better yet, make the two parameter method lastIndexOf call the 3 parameters version of lastIndexOf with the deep parameter set to 0

You can also use Matcher in order to anticipate evolution of string analysis asked by your homework:
public int getlastMatch(String searchPattern,String textString) {
int index = -1;
Pattern pattern = Pattern.compile(searchPattern);
Matcher matcher = pattern.matcher(textString);
while(matcher.find()) {
index = matcher.start();
}
return index;
}
where textString may be your concerned character.
Thus returning the last occurence of a part of string within a string.

Related

Recursive implementation of indexOf

I've already read many previous questions here and elsewhere, but I haven't found what I need.
I need to write a recursive implementation of indexOf. The problem is that I can't use any local variables and have to give as input only a string and a char.
The method should return a value between 0 and the length of the string - 1 if the char has been found or -1 if it is not there.
I know the actual 'indexOf' allows you to search for a string too, but this method is simplified.
I tried this but it's quite stupid since I used the real indexOf:
public static int indexOf(String s, char c){
if(s.indexOf(c) < 0){ // I'd like to change this
return -1;
}
if (s.length() == 0) //base case #1
{
return -1;
}
else if (s.charAt(0) == c) //base case #2
{
return 0;
}
else {
return 1 + indexOf(s.substring(1), c);
}
}
I saw this in particular, but is it possibile to write it without variables? Thanks
If you don't want local variables, you need to do the recursion in an internal method.
Advantage is that it's a lot faster, since it doesn't have to create new String objects, and the logic is tail-recursive, if used with a language that optimizes that.
public static int indexOf(String s, char c) {
return indexOf0(s, c, 0);
}
private static int indexOf0(String s, char c, int index) {
if (index == s.length())
return -1;
if (s.charAt(index) == c)
return index;
return indexOf0(s, c, index + 1);
}
The answer that you linked seems to be a good one... I recommend simply replacing the instances of the variable used in it with the method call the variable stores.
Below I simply edit the code:
public static int indexOf(char ch, String str) {
// Returns the index of the of the character ch
if (str == null || str.equals("")) {
// base case: no more string to search; return -1
return -1;
} else if (ch == str.charAt(0)) {
// base case: ch is at the beginning of str; return 0
return 0;
}
return indexOf(ch, str.substring(1)) == -1 ? -1 : 1 + indexOf(ch, str.substring(1));
}

Trying to return true if all the letters in a string are the same

What I have so far:
public boolean allSameLetter(String str)
{
for (int i = 1; i < str.length(); i++)
{
int charb4 = i--;
if ( str.charAt(i) != str.charAt(charb4))
{
return false;
}
if ( i == str.length())
{
return true;
}
}
}
Please excuse any inefficiencies if any; still relatively new to coding in general. Am I lacking some knowledge in terms of using operators and .charAt() together? Is it illogical? Or is my error elsewhere?
Using regex:
return str.matches("^(.)\\1*$");
Using streams:
str.chars().allMatch(c -> c == str.charAt(0));
Other:
return str.replace(String.valueOf(str.charAt(0), "").length() == 0;
You can follow the below steps:
(1) Get the first character (i.e., 0th index)
(2) Check the first character is the same with subsequent characters, if not return false (and comes out from method)
(3) If all chars match i.e., processing goes till the end of the method and returns true
public boolean allSameLetter(String str) {
char c1 = str.charAt(0);
for(int i=1;i<str.length;i++) {
char temp = str.charAt(i);
if(c1 != temp) {
//if chars does NOT match,
//just return false from here itself,
//there is no need to verify other chars
return false;
}
}
//As it did NOT return from above if (inside for)
//it means, all chars matched, so return true
return true;
}
As Andrew said, you are decreasing i within your for loop. You can fix this by changing it to int charb4 = i - 1;. As for making your code more efficient you could condense it down to this.
public boolean allSameLetter(String str) {
for(char c : str.toCharArray())
if(c != str.charAt(0)) return false;
return true;
}
Comment if you don't understand a part of it :)
public boolean allSameLetter(String str)
{
for (int i = 1; i < str.length() -1; i++)
{
if ( str.charAt(i) != str.charAt(i+1))
{
return false;
}
}
return true
}
-1 is there since I am checking the current value in the array, then the next value in the array, thus I need to stop a place earlier.
If the loop if statement is never entered, it will make it far enough into the code to return true
You have to create a for loop that searches through the length of the String - 1. this way the program will not crash because of a 3 letter word with the program trying to get the 4th letter. This is what works for me:
public boolean allSameLetter(String str)
{
for(int i = 0; i< str.length()-1; i++){
if (str.charAt(i) != str.charAt(i+1)){
return false;
}
}
return true;
}
if((new HashSet<Character>(Arrays.asList(s.toCharArray()))).size()==1)
return true;
return false;
This should be enough
The bug is caused by
int charb4 = i--;
this line is equal to
int charb4 = i-1;
i=i-1;
Because of this, your loop will never stop.
The easiest way to fix this
public boolean allSameLetter(String str)
{
for (int i = 1; i < str.length(); i++)
{
if ( str.charAt(i) != str.charAt(i-1))
{
return false;
}
}
}

Rewriting a for loop as recursive method?

I am having trouble rewriting the following code as a recursive method rather than using the for loop. The for loop tests to see if the String 'noSpaces' is a palindrome (the same forwards as it is backwards). The noSpaces String has no punctuation, spaces, or differences in capitalization.
Thanks for the help
public boolean isRegularPalindrome(String noSpaces) {
noSpaces = noSpaces.toUpperCase();
String[] letters = new String[noSpaces.length()];
for (int i = 0; i < letters.length; i++) {
letters[i] = Character.toString(noSpaces.charAt(i));
}
for (int i = 0; i < letters.length / 2; i++) {
if (!letters[i].equals(letters[letters.length - i - 1])) {
return false;
}
}
return true;
}
There you go:
public static boolean isPalindrome(String input) {
if (input.charAt(0) != input.charAt(input.length() - 1)) {
// Missmatch. Not a palindrome!
return false;
} else if (input.length() > 1){
// If there is more to test, continue.
return isPalindrome(input.substring(1, input.length() - 1));
} else {
// All chars were tested, or 1 char input. Palindrome!
return true;
}
}
Writing a recursive algorithm for anything requires base cases. For a palindrome, this would be a string of length 0 or length 1 -- if the string is length 0 or 1, it is a palindrome.
If the base cases aren't met, you check the first character against the last character.
If the characters aren't the same, return false.
If the characters are the same, return the recursive call to the string except for the first and last characters.
The code should look something like this.
public boolean isPalindrome(string str){
if (str.length == 0)
return true;
else if (str.length == 1)
return true;
else if(str.charAt(0) != str.charAt(str.length - 1)
return false;
else
return isPalindrome(str.substring(1, length - 1));
}

counting special characters with recursion

I'm trying to code this one up,but I don't get an expected result:
Given a string, compute recursively (no loops) the number of lowercase 'x' chars in the string.
countX("xxhixx") → 4
countX("xhixhix") → 3
countX("hi") → 0
Here is my method:
public int countX(String str) {
int count = 0;
if(str.length() >= 1 ) {
if(str.substring(0, 1).equals("x")) {
str = str.substring(1, str.length());
count = count + 1 + countX(str);
}
}
else {
str = str.substring(1, str.length());
count = count + countX(str);
}
return count;
}
You had the right idea, but I think you over complicated things. Just check explicitly if the first character is x (as you have), and only increment count in that case. Regardless of whether it was or wasn't, continue recursing on:
public static int countX(String str) {
int count = 0;
if (str.length() > 0) {
if (str.substring(0, 1).equals("x")) {
++count;
}
str = str.substring(1, str.length());
count += countX(str);
}
return count;
}
Suppose you have a string "axbxcx". The code below looks only at the first character in the string and determines if it is an x. If so, then return 1 in addition to the number of x's found in the rest of the string. If the first character is not an x, then the number of x's in the string is equal to the number of x's in the string not including the first character, so that is what is returned.
int count(String s)
{
if (s.length() == 0) // base case
{
return 0;
}
if (s.charAt(0) == 'x')
{
return 1 + count(s.substring(1));
}
else
{
return count(s.substring(1));
}
}
How about this?
public static int countX(String str) {
if (str.length() == 0) {
return 0;
}
if (str.substring(0, 1).equals("x")) {
return 1 + countX(str.substring(1));
}
return countX(str.substring(1));
}
You should try this (it assumes you are testing outside the method that initial str value is not null and has a length greater than 0).
public int countX(String str) {
if ( str.length() == 1 ) {
return ("x".equalsTo(str) ? 1 : 0);
} else {
return (str.charAt(0) =='x' ? 1 : 0) + countX(str.substring(1,str.length())
}
}
Here is a simple way to do it.
First, check if the string is empty. This is the terminating condition of the recursion.
Then your result is simply the count for the first character (1 or 0), added to the count for the rest of the string (calculated by calling your function on substring(1)).
public static int countX(String str) {
if (str.isEmpty()) {
return 0;
}
return (str.charAt(0)=='x' ? 1 : 0) + countX(str.substring(1));
}
you can try this one:
public int countX(String str) {
int end = str.length(); //get length of the string
int counter = 0;
if(str.length()==0){
return counter; //recursion will stop here
}else{
if(str.charAt(end-1) == 'x'){
counter++;
}
end--;
str=str.substring(0,end); //your string will perform a decrease in length and the last char will be removed
}
return counter+countX(str);
}

Trying to count blank spaces in a string recursively?

EDIT: Really sorry, I mean Java! As for what I think, I would say the first contains if statement is for s == null or length 0, but I'm confused as to what to put in the
return spaceCount(s.substring(1, ......)) + ......;
part.
I'm trying to use some if statements to write a function that takes a string as a parameter and recursively coutns the number of blanks spaces " " it has. So far I have
public static int spaceCount (string s) {
if ( ...... ) {
return 0;
}
char c = s.charAt(0);
if (....... ) {
return spaceCount (.....);
} else {
return spaceCount(s.substring(1, ......)) + ......;
}
}
So in the first if statement, should I write the case of the string having zero length? I'm pretty sure that won't cover the case of no spaces at all, so I'm not sure how to proceed.
For the second and third, I know I have to scan the string for spaces, but I am not really sure how to do that either. Any hints or direction would be appreciated!
public static int spaceCount(final String s) {
if(s == null || s.length() == 0) {
return 0;
}
char c = s.charAt(0);
if(' ' != c) {
return spaceCount(s.substring(1));
} else {
return spaceCount(s.substring(1)) + 1;
}
}
You don't have to "scan the string for spaces", that's what the recursion passing the remainder of the string does.
s.length() - s.replaceAll(" ", "").length() returns you number of spaces.
how to count the spaces in a java string? has the answer. Probably it may help. the above line is the simplest.
[You didn't specify a programming language] Here is a solution in Java:
public static int spaceCount(String s)
{ return scRecursive (s, s.length, 0, 0); }
public static int scRecursive (String s, int len, int dex, int count)
{ if (len == dex) return count;
else
return scRecursive (s, len, dex + 1,
(' ' == s.charAt(dex) ? count + 1 : count)); }
This is tail recursive (which might imply some efficiency) and, more importantly, this does not copy/allocate substrings
Here is one in Scheme:
(define (space-count string)
(let ((length (string-length string)))
(let stepping ((index 0) (count 0)
(if (= index length)
count
(let ((char (string-ref string index)))
(stepping (+ index 1)
(if (equal? #\space char)
(+ 1 count)
count)))))))
The recursion is in the call to stepping which has two arguments - the current index and the current count of spaces. The recursion terminates when the index equals the length. The count is incremented when the current char is a space.
public class CountSpaces {
public static void main(String[] args) {
String str = " A ";
System.out.println(spaceCount(str, 0));
System.out.println(spaceCount(str));
}
public static int spaceCount(String str, int count) {
if (str == null) {
return 0;
} else if (str.length() > 0) {
char c = str.charAt(0);
if (Character.isWhitespace(c)) {
count++;
}
return spaceCount(str.substring(1), count);
} else {
return count;
}
}
public static int spaceCount(String s) {
if (s.length() == 0 || s == null) {
return 0;
}
char c = s.charAt(0);
if (!Character.isWhitespace(c)) {
return spaceCount(s.substring(1));
} else {
return spaceCount(s.substring(1, s.length())) + 1;
}
}
}

Categories

Resources