I want to count number of words in my string using recursive method (java)
so far i wrote this code
public static int CountWords(String sen) {
int count = 0;
int i = sen.indexOf(" ");
if (sen.isEmpty()) {
return 0;
}else
if (i == sen.indexOf(" ")) {
return count++;
}
//sen.substring(0,sen.indexOf(" ")-1);
count++;
return count + CountWords(sen.substring(i + 1));
}
i always get 0 when i call the method
can anyone help me make this code run
How you're using indexOf is the problem. You're setting i to the result of calling indexOf, then seeing if it's equal to the result of calling indexOf on the same string with the same parameter. The result of the test i == sen.indexOf(" ") will always be true. That's why you always get 0.
String#indexOf returns -1 if the char it's looking for is not found. indexOf comes in very handy here.
Also you shouldn't need a local count variable. Introducing a variable here just makes the code harder to read, because the reader has to hunt around to figure out what the value of it is.
Assuming your input always has exactly one blank between words this could be done as:
public static int countWords(String s) {
if (s.isEmpty()) return 0;
if (s.indexOf(" ") == -1) return 1;
return 1 + countWords(s.substring(s.indexOf(" ") + 1));
}
For multiple blanks between words you can check for a blank and skip past it:
public static int countWords(String s) {
if (s.isEmpty()) return 0;
if (s.indexOf(' ') == -1) return 1;
if (s.charAt(0) == ' ') return countWords(s.substring(1));
return 1 + countWords(s.substring(s.indexOf(' ') + 1));
}
This should work, I think:
public static int countWords(String sen) {
int i = sen.indexOf(" ");
if (sen.isEmpty()) {
return 0;
} else if (i == -1) {
return 1;
} else return 1 + countWords(sen.substring(i + 1));
}
Some notes on what is happening:
Java naming conventions dictate you should start method names with a lower case letter
The line if (i == sen.indexOf(" ")) is redunant - you just assigned i to be that before, so it'll always evaluate to true.
And therefore, your recursion never gets called. You need to change it so that if sen isn't empty and contains at least one more space, countWords calls itself with sen minus the first word.
This method uses a String with no spaces as a base case. Then it removes everything up to and including the first space in the String and recurses.
It handles both the special case of an empty String and the case that a String passed to the method starts with a space appropriately.
public static int CountWords(String sen)
{ int i = sen.indexOf(" ");
if(sen.isEmpty()) return 0; // special case
if(i == -1) return 1; // base case
if(i != 0)
return 1 + CountWords(sen.substring(i+1));
else
return CountWords(sen.substring(1));
}
This will work -
public static int CountWords(String sen) {
if("".equals(sen)){
return 0;
}
int count = 0;
int i = sen.indexOf(" ");
String substr = sen.substring(0,i+1) ;
if (i != -1) {
count++;
}else{
if(sen.length()>0){
count++;
}
sen="";
}
//sen.substring(0,sen.indexOf(" ")-1);
return count + CountWords(sen.substring(substr.length()));
}
Related
I am currently creating a java program that counts the number of occurrences of a specific word in a string using recursion, however, if the preceding letter is an 'a', the count won't be incremented. I cannot find a way to check the preceding letter before the first letter of the word I am looking for. I tried using indexOf then subtracting one to check the preceding letter, but it won't work.
Here's my working function at the moment:
//The value of text is abrichbbarichacrich
//While the value of find is rich
//Expected output should be 2
static int Count(String text, String find) {
if (text.length() == 0 || text.length() < find.length()) {
return 0;
}
if (text.contains(find)) {
return 1 + Count(text.replaceFirst(find, ""), find);
}
return 0;
}
Here's my second version, but it gives me a StringIndexOutOfBoundsException and the output should be 2, but instead it gives me an output of 3.
if (text.length() == 0 || text.length() < find.length()) {
return 0;
}
if (text.contains(find)) {
int index = text.indexOf(find) - 1;
if (text.charAt(index) == 'a')
return Count(text.replaceFirst(find, ""), find);
return 1 + Count(text.replaceFirst(find, ""), find);
}
Any help would be appreciated :)
Correct if else condition .replaceFirst() method returns the updated string.We have to update the string.
static int Count(String text, String find) {
if (text.length() == 0 || text.length() < find.length()) {
return 0;
}
if (text.contains(find)) {
int index = text.indexOf(find) - 1;
text=text.replaceFirst(find, "");
if (index!=-1&&text.charAt(index) != 'a'){
return 1+Count(text,find);
}
else
return Count(text,find);
}
return 0;
}
Just working the answer out in pseudocode, here's how I'd approach the problem.
Define a helper function as follows:
countHelper(string text, string find, bool previousWasNotA) =
if (length of text < length of find) {
0
} else {
let prefixEqualsFind = if (previousWasNotA and find is a prefix of text) {
0
} else {
1
}
in
prefixEqualsFind + countHelper(text without first character, find, first character of text != 'a')
}
count(string text, string find) = countHelper(text, find, true)
The idea here is that countHelper(text, find, previousWasNotA) returns the number of occurences of find in text, not counting any occurences where find is directly preceded by an a, and not counting an occurence of find at the very beginning of text if previousWasNotA is false.
In Java, this look like
static int countHelper(String text, String find, bool previousWasNotA) {
if (text.length() < find.length()) {
return 0;
} else {
const int prefixEqualsEnd = previousWasNotA && text.startsWith(find) ? 1 : 0;
return prefixEqualsEnd + countHelper(text.substring(1), find, text.charAt(0) != 'a');
}
}
static int count(String text, String find) {
return countHelper(text, find, true);
}
Note that this doesn't work for the case of find = "". But in that case, it's not clear the problem even has an answer at all, since we can put infinitely many ""s together to make a single "" and hence infinitely many ""s are contained in any string at all.
Also note that this is not an asymptotically optimal algorithm. For that, you'll want to use the KMP algorithm.
So the program has to count letters of a string. I am not allowed to use loops except of recursive ones.
The method has to look like this:
static int numberOf(String text, char characterToCount)
Input:
abcbabcba (String) and b (char)
Output:
4
That's what my Code looks like so far ( I get Stackoverflow ) :
static int numberOf(String text, char characterToCount) {
int i = 0;
int erg = 0;
if (text.length() != 0) {
if (i != text.length()) {
if (text.charAt(i) == characterToCount) {
i++;
erg++;
numberOf(text, characterToCount);
} else {
i++;
numberOf(text, characterToCount);
}
} else {
return erg;
}
}
return 0;
}
EDIT
I'm only allowed to use String.charAt and String.length
The problem is that you aren't reducing text when you call the method so the length is never reduced to 0. Here is what you should be doing. Note that you do not need to pass an index to the method. Just keep reducing the text by 1 each time and just check the first character for equality to the target character.
public static void main(String[] args) {
System.out.println(numberOf("ksjssjkksjssss", 's'));
}
static int numberOf(String text, char characterToCount) {
if (text.isEmpty()) {
return 0;
}
if (text.charAt(0) == characterToCount) {
// call method and add 1 since you found a character
return numberOf(text.substring(1), characterToCount) + 1;
}
// just call the method.
return numberOf(text.substring(1), characterToCount);
}
The above prints
8
Ok, here is my modified version to meet your requirements of using only String.length and String.charAt. The char is really 16 bits so I use the high order byte to store the current index. I increment that index for each recursive call to maintain the current position of the search. When I add 256 to the character I am really adding 1 to the high order byte.
static int numberOf(String text, char ch) {
// stop when index exceeds text length
if (ch >> 8 >= text.length()) {
return 0;
}
if (text.charAt((ch >> 8)) == (ch & 0xff)) {
return numberOf(text, (char)(ch + 256)) + 1;
}
return numberOf(text, (char)(ch + 256));
}
This will not work as written on some character sets that are wider than 8 bits.
WJS's answer looks good but if you want simpler solution, this might help as well.
The problem in your solution is that your update of i and erg in one call stack is not seen/used by the next recursive call stack, since they are local variables and every stack will have their own copy of i and erg. They are always initialized as 0 in every call of numberOf method.
If substring isn't allowed then one way would be to make use of an extra variable that holds the index of position in the text you are comparing.
But on doing so you'll probably have to modify the signature of your method (if you don't want to use a class level static variable). And since you've mentioned that your method has to have only two arguments (text, charToCount), one way to achieve this easily would be to make use of a helper method (containing extra index argument) and your method can call it.
static int numberOf(String text, char characterToCount) {
return helper(text, characterToCount, 0);
}
static int helper(String text, char charToCount, int index) {
if (text.isEmpty() || index == text.length()) return 0;
int countCharOnRight = helper(text, charToCount, index+1);
return (text.charAt(index) == charToCount) ? 1 + countCharOnRight : countCharOnRight;
}
What
static int numberOf(String text, char characterToCount) {
return numberOfRecursive(text, characterToCount, 0);
}
// Recursive helper function
static int numberOfRecursive(String text, char characterToCount, int index) {
if (index == text.length()) // Abort recursion
return 0;
if (text.charAt(index) == characterToCount) // check char at index, then check next recursively
return numberOfRecursive(text, characterToCount, index + 1) + 1;
else
return numberOfRecursive(text, characterToCount, index + 1);
}
Why
Most recursive problems require a helper function, that actually performs the recursive part. It will be called from the original function with initial values, here with our text, character and a starting position of 0.
Then, the recursive function needs an abort condition, which I provide by a bound check. We terminate if our recursion reached the end of the string.
Finally the recursive function does some calculation which it bases on a recursive call. Here we add 1 to our result, if the char at our index position is the one to count. If not, we continue counting without adding 1.
I hope I could help.
The idea of recursion is that you call the same function/method a lot of times after some conditions. A good approach is to call the same function but reduce the string to check each time.
Class
public class StringUtils {
public int numberOf(String text, char characterToCount) {
int count = 0;
if (text.length() != 0) {
if(text.charAt(0) == characterToCount) { //Only increment when is the same character
count++;
}
count = count + numberOf(text.substring(1, text.length()), characterToCount); //Do a substring but remove the first character
}
return count;
}
}
Test
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class StringUtilsTest {
#Test
public void should_count_all_the_ocurrences() {
//Given
StringUtils utils = new StringUtils();
String sentence = "</www></palabraRandom></www></palabraRandom></palabraRandom></www>";
//When
int output = utils.numberOf(sentence, '>');
//Then
assertEquals(6, output);
}
}
So I think I got my solution.
It's maybe not that well but it works. Thanks for your help :)
public class CountLetters {
public static void main(String[] args) {
print("Bitte geben Sie den Text ein: ");
String text = readString();
text = toLowerCase(text, 0);
print("Bitte geben Sie ein Zeichen ein: ");
String zeich = readString();
zeich = toLowerCase(zeich, 0);
if (zeich.length() > 1) {
throw new PR1Exception("Bitte nur einen Buchstaben eingeben. ");
}
char zeichen = zeich.charAt(0);
if (zeichen > 0 && zeichen < 65 && zeichen > 90 && zeichen < 97 && zeichen > 123) {
throw new PR1Exception("Bitte nur Buchstaben eingeben.");
}
int anzahl = numberOf(text, zeichen);
println("-> " + anzahl);
}
static String toLowerCase(String text, int i) {
String lowerText = "";
if (i == text.length()) {
return lowerText;
} else if (text.charAt(i) < 'a') {
return lowerText += (char) (text.charAt(i) - 'A' + 'a') + toLowerCase(text, i + 1);
} else {
return lowerText += text.charAt(i) + toLowerCase(text, i + 1);
}
}
static int numberOf(String text, char characterToCount) {
return hilfe(text, characterToCount, 0, 0);
}
static int hilfe(String t, char ch, int i, int a) {
if (t.length() == a) {
return i;
} else if (t.charAt(a) == ch) {
return hilfe(t, ch, i + 1, a + 1);
} else {
return hilfe(t, ch, i, a + 1);
}
}
You can use an index variable if it is reached to the end returns 0. Otherwise, return 1 if it is letter or 0.
public class Main {
public static void main(String[] args) {
System.out.println(numberOf("Hello World-1234", 'o'));
}
private static int numberOf(String text, char characterToCount) {
if (!text.isEmpty()) {
return numberOf(text.substring(1), characterToCount) + (text.charAt(0) == characterToCount ? 1 : 0);
}
return 0;
}
}
EDIT: Implementation without substring
public class Main {
public static void main(String[] args) {
System.out.println(numberOf("Hello World-1234", 'o'));
}
private static int numberOf(String text, char characterToCount) {
if (text.isEmpty()) {
return 0;
}
char[] chars = text.toCharArray();
char[] newChars = new char[chars.length - 1];
System.arraycopy(chars, 1, newChars, 0, newChars.length);
return numberOf(new String(newChars), characterToCount) + (chars[0] == characterToCount ? 1 : 0);
}
}
Given a string, consider the prefix string made of the first N chars of the string. Does that prefix string appear somewhere else in the string? Assume that the string is not empty and that N is in the range 1..str.length().
public boolean prefixAgain(String str, int n) {
String res = "";
String res1 = "";
String s = str.substring(0,n);
for ( int i = 0 ; i < n ; i++ ) {
res += str.charAt(i) ;
if (s.equalsIgnoreCase(res)); {
return true;
} else {
return false;
}
}
}
There are many problems with your solution:
Why do you need to loop only till n in the prefixAgain method? You probably need to go till str.length()
Your res variable will again be a prefix of the string and will be of no use.
Why are you having ; after the if?
Using += on Strings in a loop can be very expensive. You should always consider using StringBuilder and it's append method.
The following method does what you want:
public boolean prefixAgain(String str, int n) {
if (str.length() == 1) return false;
String s = str.substring(0, n);
return str.substring(1).contains(s);
}
The main idea is to just search the required prefix in the substring starting from 2nd character (the character at index 1).
Keep it simple. :)
I need an algorithm that verify with the fastest possible execution time, if a string is a palindrome ( the string can be a proposition with uppercase or lowercase letter, spaces etc.). All of this in Java. I got a sample :
bool isPalindrome(string s) {
int n = s.length();
s = s.toLowerCase();
for (int i = 0; i < (n / 2) + 1; ++i) {
if (s.charAt(i) != s.charAt(n - i - 1)) {
return false;
}
}
return true;
}
I transformed the string in lowercase letter using .toLowerCase() function, but I don't know how much it affects the execution time .
And as well I don't know how to solve the problem with punctuation and spaces between words in a effective way.
I think you can just check for string reverse, not?
StringBuilder sb = new StringBuilder(str);
return str.equals(sb.reverse().toString());
Or, for versions earlier than JDK 1.5:
StringBuffer sb = new StringBuffer(str);
return str.equals(sb.reverse().toString());
This avoids any copying. The functions isBlank and toLowerCase are rather unspecified in your question, so define them the way you want. Just an example:
boolean isBlank(char c) {
return c == ' ' || c == ',';
}
char toLowerCase(char c) {
return Character.toLowerCase(c);
}
Don't worry about the costs of method calls, that's what the JVM excels at.
for (int i = 0, j = s.length() - 1; i < j; ++i, --j) {
while (isBlank(s.charAt(i))) {
i++;
if (i >= j) return true;
}
while (isBlank(s.charAt(j))) {
j--;
if (i >= j) return true;
}
if (toLowerCase(s.charAt(i)) != toLowerCase(s.charAt(j))) return false;
}
return true;
Try to benchmark this... I'm hoping mu solution could be the fastest, but without measuring you never know.
Your solution seems just fine when it comes to effectiveness.
As for your second problem, you can just remove all spaces and dots etc before you start testing:
String stripped = s.toLowerCase().replaceAll("[\\s.,]", "");
int n = stripped.length();
for (int i = 0; i < (n / 2) + 1; ++i) {
if (stripped.charAt(i) != stripped.charAt(n - i - 1)) {
...
Effective is not the same of efficient.
Your answer is effective as long you consider spaces, special characters and so on. Even accents could be problematic.
About efficiency, toLowerCase is O(n) and any regexp parsing will be O(n) also. If you are concerning about that, convert and compare char by char should be the best option.
Here is my try:
public static boolean isPalindrome(String s)
{
int index1 = 0;
int index2 = s.length() -1;
while (index1 < index2)
{
if(s.charAt(index1) != s.charAt(index2))
{
return false;
}
index1 ++;
index2 --;
}
return true;
}
Here's some insight to my way of detecting a palindrome using Java. Feel free to ask question :) Hope I could help in some way....
import java.util.Scanner;
public class Palindrome {
public static void main(String[]args){
if(isReverse()){System.out.println("This is a palindrome.");}
else{System.out.print("This is not a palindrome");}
}
public static boolean isReverse(){
Scanner keyboard = new Scanner(System.in);
System.out.print("Please type something: ");
String line = ((keyboard.nextLine()).toLowerCase()).replaceAll("\\W","");
return (line.equals(new StringBuffer(line).reverse().toString()));
}
}
In normal cases :
StringBuilder sb = new StringBuilder(myString);
String newString=sb.reverse().toString();
return myString.equalsIgnoreCase(newString);
In case of case sensitive use :
StringBuilder sb = new StringBuilder(myString);
String newString=sb.reverse().toString();
return myString.equals(newString);
I am trying to solve this String manipulation problem, where I need to find the smallest period of a given string.
A string is said to have period k if it can be formed by concatenating one or more repetitions of another string of length k.
For example, the string "abcabcabcabc" has period 3, since it is formed by 4 repetitions of the string "abc". It also has periods 6 (two repetitions of "abcabc") and 12 (one repetition of "abcabcabcabc"). Here's my code :
public static int getPeriod(String str){
int len=str.length();
boolean flag=false;
int i;
for (i=0;i<len;i++){
String s=str.substring(0,i);
String tmp=str;
while(tmp.length()>0){
if(tmp.startsWith(s)){
tmp=tmp.substring(0,i);
flag=true;
}
else {
flag=false;
continue;
}
}
if (flag==true)
break;
}
return i;
}
I am forming a string s by looping through the original string, one character at a time. After, that I am checking if the original string can be completely exhausted by concatenating the string s any number of times, or not.
ERROR:
The method always returns 0.
Why is that so ?
EDIT : My algorithm
Lets consider the input string HoHoHo
First step: s=H
tmp= HoHoHo
tmp= oHoHo (after substringing tmp)
'o' isn't the same as s, so we increase i
Second step:s=Ho
tmp= HoHoHo
tmp= HoHo (after substringing tmp)
tmp= Ho (after substringing tmp)
tmp= "" (after substringing tmp)
Return the value of i, that is 2.
The code inside the while loop isn't correct, it's called during the first invocation of the for loop with i=0 and hence the first assignment to the tmp variable sets it to the empty string, the loop exits and you get 0. The flag assignments and the continue in the else are not correct too.
Try this:
public static int getPeriod(String str) {
int len = str.length();
int i;
for (i = 1; i <= len/2; i++) {
String period = str.substring(0, i);
String tmp = str;
boolean flag = true;
while (flag && tmp.length() > 0) {
if (tmp.startsWith(period)) {
tmp = tmp.substring(i);
} else {
flag = false;
}
}
if (flag == true) {
return i;
}
}
return 0;
}
Notice that the for loop starts from 1 and goes to len/2 because you don't want to check for the zero length period and there can't be periods longer than n/2.
In the first loop iteration, i == 0, so s is "" (empty string), and tmp is also "" after the first iteration over while loop, so tmp also becomes "" and exits all the loops.
Starting with i = 0 will always return true because substring(0,0) will return the "" string and tmp.startsWith("") is always true.
First you should start i from 1, also you should replace continue with break, because continue will continue your while loop but what you want to do is continue the for loop and not the while loop
Here is a version of your code working:
public static int getPeriod(String str){
int len=str.length();
boolean flag=false;
int i;
for (i=1;i<len;i++){
String s=str.substring(0,i);
String tmp=str;
while(tmp.length()>0){
if(tmp.startsWith(s)){
tmp=tmp.substring(i);
flag=true;
}
else {
flag=false;
break;
// Replaced continue with break to exit the while loop and pass
// to the next value in the for loop
}
}
if (flag==true)
break;
}
return i;
}
I know this is an old question. The problem can be solved in linear time using Knuth's Prefix Function.
public static int prefixFunction(final String needle)
{
//This code does not include input validation. Validate the input and return appropriate error message
int[] pf = new int[needle.length()];
for (int i = 1; i < needle.length(); i++)
{
int j = pf[i - 1];
while (j > 0 && needle.charAt(i) != needle.charAt(j)) j--;
if (needle.charAt(i) == needle.charAt(j)) ++j;
pf[i] = j;
}
int n = needle.length(), maxValue = pf[n - 1];
if(maxValue == 0 || n%(n-maxValue) != 0) return -1; //Not periodic
return needle.length() - maxValue;
}