Im making a program to count the number of times a character is found in a string. This is what my method looks like:
public static int count (String line, char c)
{
int charOccurences = 0; //= 0;
for (int x = 0 ; x < line.length () ; x++)
{
if (line.charAt (x) == c)
{
charOccurences++;
line = line.substring (0, x) + line.substring (x + 1);
return count (line, c);
}
else
return charOccurences;
}
return charOccurences;
}
It always returns 0, due to the fact that once the method calls itself it sets charOccurences back to 0. But i need to declare that variable for the method to work. I cant figure any way around this. Any help would be appreciated.
You ignored charOccurences right after you incremented it.
charOccurences++;
line = line.substring (0, x) + line.substring (x + 1);
return charOccurences + count (line, c); // Fixed for you.
Others have mentioned that you don't need a for loop at all. If you wanted to do this purely recursively, you would simply lose the loop, and follow these steps:
base case:
first character doesn't exist (length is zero)
return 0;
recursion case:
The first character does exist
if it matches, increment occurrences
else do nothing
return (occurrences) + (result of recursing with substring);
Yea, it is very easy to do it recursively :)
public static void main(String[] args) {
String text = "This is my text. Life is great";
System.out.println(count(text,'i',0));
}
public static int count(String line, char c, int pos) {
if (pos >= line.length()){
return 0;
}
return compare(line.charAt(pos), c) + count(line, c, pos+1);
}
public static int compare(char a, char b){
if (a == b){
return 1;
} else {
return 0;
}
}
Note that thanks to not substringing every time, time complexity is O(n) instead of yours O(n^2)
Here's a general approach for writing recursive methods for tasks that really shouldn't be recursive but have to be because you're learning about recursion in class:
Find a way to break the problem down into a smaller problem(s).
Here, your problem is to count the occurrences of character c in a string. Well, suppose you break your string down into "the first character" and a substring of "all the other characters". You can tell whether the first character equals c. Then you look at "all the other characters", and if that's not empty (the base case), then that's just a smaller version of the same problem. So you can use recursion on that. So pretend the recursion already happened, so then you know: (1) is the first character equal to c, and (2) how many occurrences of c are there in the smaller string. Once you know those two pieces of data, you should be able to figure out how many occurrences of c there are in the whole string.
For this problem, your solution should not have a loop in it.
You never actually increment count. You just keep returning count. At the very end of your recursive stack, count will return 0, as that is what you initialize count to at the begining of every method call, and it will keep returning zero until it gets to the bottom of the stack, then return 0. You need to do this:
charOccurences += count (line, c);
return charOccurences;
so charOccurences will start at 1 at the first occurence, then propagate up.
I think you're making it much harder than it needs to be?
public static int count(String line, char c) {
int orig = line.length();
int repl = line.replaceAll("" + c, "").length();
return orig - repl;
}
Despite doing it recursively is not required (let's do it for fun). You were almost done. Just be sure to have a condition that stops the recursion: here it is if (len == 0)… statement.
public static int count (String line, char c)
{
int len = line.length();
if ((len == 0) || (c == '\0')) // obvious case for empty string or nil char.
return 0; // Your recursion always ends here
String rest = line.substring(1);
if (line.charAt(0) == c)
{
return count(rest, c) + 1; // recurse on substring
}
else
{
return count(rest, c); // recurse on substring
}
}
i had the same issue you can always do this i did it on a word same applies for a sentence
private static int count(String word, String letter) {
int count = 0;
return occurrence(word, letter, count);
}
private static int occurrence(String word, String letter, int count) {
if ()
base case
else
// compare and increment if it matches..
return occurrence(word.substring(0, word.length() - 1), letter,count)
}
the other method occurrence be the recursion method,
and repeat your code now count is already defined and you can increment without having any problem! :)
Please remove the else loop inside the for loop. If you keep that loop you should get occurrence of only one character.
public static int count (String line, char c)
{
int charOccurences = 0; //= 0;
for (int x = 0 ; x < line.length () ; x++)
{
if (line.charAt (x) == c)
{
charOccurences++;
line = line.substring (0, x) + line.substring (x + 1);
return count (line, c);
}
}
return charOccurences;
}
Related
public int lookFor(String s) {
final int EXIST = 1;
final int NOT_EXIST = -1;
int thisIndex = 0;
int otherIndex = 0;
char thisNext;
char otherNext;
if (s == null || s.length() == 0)
return NOT_EXIST;
for(; thisIndex < this.mainString.length() ; ) {
thisNext = this.mainString.charAt(thisIndex);
otherNext = s.charAt(otherIndex);
if (thisNext == otherNext) {
thisIndex++;
otherIndex++;
}
else if (thisNext != otherNext)
thisIndex++;
if (otherIndex == s.length()-1)
return EXIST;
}
return NOT_EXIST;
}
This is my attempt so far.
mainString = the main string I want to find the substring in.
s = the substring.
So my idea was to get the first chars of both strings, see if they equal. if they don't, i'll get the second char of mainString, see if they equal (mainString second char to s first char). If they're not equal, i'll get the third char of mainString and so forth. Once they're equal, i'll get the next char of both strings and see if they both equal.
Basically the loops knows that mainString contains s when index of s equals to s length minus one (that means the loop looped all the way to the last char inc, of s, so s index == s length -1).
Is the logic I'm trying to work with incorrect? or I just executed it not good? i'll happy to get answers!
Here's my naïve approach:
private final int EXIST = 1;
private final int NOT_EXIST = -1;
private int lookFor(String a, String b, int index) {
for (int i = 0; i < b.length(); i++) {
if ((index + i) >= a.length()) return NOT_EXIST;
if (a.charAt(index + i) != b.charAt(i)) return NOT_EXIST;
}
return EXIST;
}
public int lookFor(String a, String b) {
char start = b.charAt(0);
for (int i=0; i < a.length(); i++) {
if (a.charAt(i) == start) {
if (lookFor(a, b, i) == EXIST) return EXIST;
}
}
return NOT_EXIST;
}
Though, I'm not sure why you would do this when you could just do:
int ret = a.contains(b) ? EXIST : NOT_EXIST
However I wanted to actually answer your question.
Here's a slightly improved version that satisfies your "all in one method" requirement.
public static int lookFor(String a, String b) {
// Fancy way of preventing errors when one of the strings is empty
boolean az = a.length() == 0;
boolean bz = b.length() == 0;
if (az ^ bz) return NOT_EXIST;
// Need this next line if you want to interpret two empty strings as containing eachother
if (az && bz) return EXIST;
char start = b.charAt(0);
// This is known as a "label". Some say it's bad practice.
outer:
for (int i=0; i < a.length(); i++) {
if (a.charAt(i) == start) {
// Instead of using two methods, we can condense it like so
for (int q = 0; q < b.length(); q++) {
if ((i + q) >= a.length()) continue outer;
if (a.charAt(i + q) != b.charAt(q)) continue outer;
}
return EXIST;
}
}
return NOT_EXIST;
}
To find a substring "by hand", you need a nested loop; i.e. a loop inside a loop.
The outer loop tries all of the possible start positions for the substring in the string.
For a given start position, the inner loop tests all of the characters of the string that you are looking for against the string you are searching in.
In the naive substring search algorithm, the outer loop steps starts at index zero, and increments the index by one until it gets to the end of the string being searched. This can be improved on:
Every non-null string "contains" the empty string. It may be worth treating this as a special case.
It is easy to see that the outer loop can usually stop before the final. If you are searching for a string of length (say) 3, then the outer loop can stop at 3 from the end. (Think about it ....)
There are some clever algorithms which allow the outer loop to skip over some indexes. If you are interested, start by Googling for "Boyer-Moore string search".
(Note: the looping could be replaced with / written using recursion, but it is still there.)
Your code doesn't have a nested loops. By my reading, it is only going to find a match if the string you are searching for is at the start of the string you are searching. That is not correct.
I'm trying to solve this question from CodingBat.com. - https://codingbat.com/prob/p143900
I run the recursion twice, then I subtract their values to give the final answer. Individually, I and J are getting the correct values, but when I do i - j, the result doesn't make sense.
public int countHi2(String str) {
if(str.length() == 0)
return 0;
int i = count(str, "hi");
int j = count(str, "xhi");
return i-j;
}
public int count(String str, String match)
{
int i = str.indexOf(match);
if(i != -1)
return 1 + countHi2(str.substring(i+match.length()-1));
else
return 0 + countHi2(str.substring(1));
}
I think you treat rescursive illegally. You should not use external method or even split a string.
public int countHi2(String str) {
if (str == null || str.length() < 2)
return 0;
if (str.startsWith("hi"))
return 1 + countHi2(str.substring(2));
return countHi2(str.substring(str.startsWith("xhi") ? 3 : 1));
}
you might wanna use:
str.substring(i+match.length())
suppose your match was on index 3 and the length of the word to match is 2, then you want the substring from index 5 to the end.
thus,
str.substring(5);
which includes the index 5
though, i don't understand why you used
return 0 + countHi2(str.substring(1));
because this condition will hold if no match is found, so what is the point of checking for a match again in a substring !!!
I cant seem to find a proper solution to an exercise. The exercise asks to create a method that returns true if a string can be a palindrome by removing one character. I have a solution that works but fails tests of large (100,000 character) strings because its exceeding the time limit of 1 second. Can somebody point me in the right direction?
I realize my approach is brute force and I'm sure there's a better way to solve it. I'm assuming my problem lies with the iteration.
public class Main {
public static boolean makePalindrome(String mjono) {
StringBuilder sb = new StringBuilder(mjono);
for (int i = 0; i < mjono.length(); i++) {
sb.deleteCharAt(i);
if(isPalindrome(sb.toString())){
return true;
} else {
sb.insert(i, mjono.charAt(i));
}
}
return false;
}
private static boolean isPalindrome(String string) {
return string.equals(new StringBuilder(string).reverse().toString());
}
public static void main(String[] args) {
System.out.println(makePalindrome("ABCBXA"));
System.out.println(makePalindrome("ABCBAX"));
System.out.println(makePalindrome("ABCXBA"));
System.out.println(makePalindrome("ABCDE"));
System.out.println(makePalindrome("BAAAAC"));
}
}
These are the tests it fails:
#Test(timeout=1000)
public void suuri2() {
int n = 100000;
char[] t = new char[n];
for (int i = 0; i < n; i++) t[i] = 'A';
t[12345] = 'B';
testaaSuuri(new String(t), true);
}
#Test(timeout=1000)
public void suuri3() {
int n = 100000;
char[] t = new char[n];
for (int i = 0; i < n; i++) t[i] = 'A';
t[12345] = 'B';
t[54321] = 'C';
testaaSuuri(new String(t), false);
}
Thanks in advance.
Well, there's of course the naive solution running in O(n ^ 2) by trying each possibility to remove one char.
But we can certainly do better:
We can define a palindrome recursively:
palindrome = x.palindrome.x | x | x.x , where x is an arbitrary token
So how does that help us? Pretty simple: we can derive a rules that allow checking whether the string is palindromic in O(n).
A palindrome consists of a char c, followed by a string that must be empty or palindromic, followed by another c, if it's longer than 1 char. If it's of length 1, it's automatically palindromic.
Thus, the last character must be equal to the first, the second to the second to the last, and so on. So basically:
boolean isPalindrome(String s){
for(int i = 0 ; i < s.length() / 2 ; i++)
if(s.charAt(i) != s.charAt(s.length() - i - 1))
return false;
return true;
}
We have to alter this rule a bit, since once we may remove a single character. This introduces splitting the whole problem into two parts, as we can see from a definition:
palindrome_1 = s.x.palindrome.reverse(s) | s.palindrome.x.reverse(s) | palindrome
As we can easily see, this contains the original palindrome-definition, but in addition allows introduction of one additional char x.
static boolean isPalindrome_1(String s){
for(int i = 0 ; i < s.length() / 2 ; i++)
if(s.charAt(i) != s.charAt(s.length() - i - 1))
return isPalindrome(s , i + 1 , s.length() - i - 1) ||
isPalindrome(s , i , s.length() - i - 2);
return true;
}
static boolean isPalindrome(String s , int lower , int upper){
while(lower < upper){
if(s.charAt(lower) != s.charAt(upper))
return false;
lower++;
upper--;
}
return true;
}
An explanation/or at least an attempt to explain this:
This piece of code:
if(s.charAt(i) != s.charAt(s.length() - i - 1))
return isPalindrome(s , i + 1 , s.length() - i - 1) ||
isPalindrome(s , i , s.length() - i - 2);
Is required, if the definition of palindrome doesn't apply to our input-string. In that case, we have to check two possibilities, how the code was built:
s.x.palindrome.reverse(s)
s.palindrome.x.reverse(s)
If the definition of palindrome doesn't apply, we have reached a point, were we have to ommit either the character of at the start of the remaining string (x.palindrome) or the end of the remaining string (palindrome.x) and see, if the rest matches the definition of a palindrome. This is done by calling isPalindrome(...) with two different substrings, that are cut by one character at either the start or the end of the remaining string.
An few examples of how this code works:
A B C D E F E D C B A
| | portion that runs inside isPalindrome_1
A B D E F E D C B A
| | | | portion that can be checked inside isPalindrome_1
| | isPalindrome(s , i , s.length() - i - 2)
| | isPalindrome(s , i + 1 , s.length() - i - 1)
As we can see in the second example, the code searched for the first pair of chars that isn't equal. At this point, we have two substrings to search further, which each ommit one character, either at the beginning or the end of the string.
Efficiency:
This code runs in-place - there are never made any copies of the input-string. Runtime is O(n) (O(2 * n) to be precise). Building a faster solution won't be possible - at least until we get quantum computers ;)
Hint 1: since this is an exercise, posting solutions is inappropriate. (It detracts from the learning experience of doing the exercise yourself.)
Hint 2: The following operations are all O(N) for an N character String or StringBuilder:
Adding or removing a character from a StringBuilder
Creating a new StringBuilder from an existing StringBuilder
Reversing a StringBuilder
Creating a String from a StringBuilder (toString())
Comparing two equal or "almost equal" String objects.
(In most cases you copy or compare N characters. For insertion and deletion, you copy on average 0.5 N characters assuming that the buffer does not need to grow, but that is still O(N). For equals ... it is complicated, but the worst-case is clearly O(N).)
So a fast palindrome tester for large strings needs to avoid these operations.
Hint 3: you can treat the string as an array of characters, either by converting it into a char[] or using charAt(...).
Hint 4: you don't have to physically remove the char from the string. You can just get your algorithm to pretend it isn't there.
We can solve this using LCS(Longest Common Sub-sequence).
LCS tells us the length of the longest sub-sequence in two strings.
boolean isPalindromAfterRemovingOneChar(String s) {
int lengthOfLCS = lcs(s, s.reverse(), s.length());
return (s.length()- lengthOfLCS) == 1;
}
function test(s) {
const check = isPalindrome(s)
if (!check) {
const arr = s.split('')
const arrCheck = []
arr.forEach((element, i) => {
if (element !== arr[arr.length - i - 1]) {
const news = Array.from(arr)
console.log(arr, news.splice(i, 1))
isPalindrome(news.join(''))
}
});
console.log('arrCheck', arrCheck)
}
function isPalindrome(s) {
var reversedString = s.split("").reverse().join("");
if (s === reversedString) {
console.log('this string is palindrome', s)
return true
} else {
console.log('no')
return false
}
test('aaab')
Only need to compare the first half to the second half. Don't waste time reversing the whole String either.
private boolean isPalindrome(String string) {
char[] values = string.toCharArray();
for (int i = 0; i < values.length / 2; i++) {
if (values[i] != values[values.length - 1 - i])
return false;
}
return true;
}
I've got a String that I need to cycle through and create every possible substring. For example, if I had "HelloWorld", "rld" should be one of the possibilities. The String method, substring(int i, int k) is exclusive of k, so if
|H|e|l|l|o|W|o|r|l|d|
0 1 2 3 4 5 6 7 8 9
then
substring(7,9) returns "rl"
How would I work around this and get it to work inclusively? I understand why a substring shouldn't be able to equal the String it was created from, but in this case it would be very helpful to me in this case.
Example from Codingbat: http://codingbat.com/prob/p137918
What I was able to come up with:
public String parenBit(String str) {
String sub;
if (str.charAt(0) == '(' && str.charAt(str.length() - 1) == ')')
return str;
for (int i = 0; i < str.length() - 1; i++) {
for (int k = i + 1; k < str.length(); k++) {
sub = str.substring(i,k);
}
}
return null;
}
The transformation between exclusive to inclusive is simple when you're working in integers. You just add 1.
String substringInclusive(String s, int a, int b)
{
return s.substring(a, b+1);
}
As Jon Skeet rightly pointed out that adding 1 would be the right thing to do as the second parameter in String.substring is not inclusive.
However your answer is not recursive, below is the recursive solution:
public String parenBit(String str) {
if(str.charAt(0)!='(')
return parenBit(str.substring(1));
if(str.charAt(0)=='('&&(str.charAt(str.length()-1)!=')'))
return parenBit(str.substring(0, str.length()-1));
return str;
}
I have an assignment introducing Recursion in Java and I am running into a roadblock. The assignment requires a recursion method to output a number of lines of a number of asterisks depending on the integer value passed to it. For example, if 4 is passed in as variable n, the output would have a first line of one asterisk, next line 2 asterisks, next 3 asterisks, next 4, then 4, 3, 2, & 1 going down.
I have been able to complete the first half of the output (not sure if it is optimal though), but have no clue how to get the method to reverse back down. This is all to be done in one method call with a variable (n) passed to the method.
Here is the method I have so far:
public static void myMethod(int n)
{
if (n <= 1) {
System.out.print("*");
} else {
myMethod(n - 1);
for (int i = 0; i < n; i++) {
System.out.print("*");
}
}
System.out.print("\n"); // new line
}
It is called from main with this:
myMethod(n);
So what I have is a for loop that will print an asterisk on the same line 'n' times. After the for loop it proceeds to the next line and cycles, changing n. But I have no idea how to get it to reverse.
My method prints from the method. My instructor showed me a sample version passing 2 variables (n) and a null string.
public static String myMethod(int n, String displayStr) {
String currentStr = "";
for (int i = 0; i < n; i++)
currentStr += "*";
currentStr += "\n";
if (displayStr == null){
return myMethod((n - 1), currentStr);
} // end base case
else if (n > 0){
return myMethod((n - 1), (currentStr + displayStr + currentStr));
}
else {
return displayStr;
}
} // end recursion method myMethod
His version prints from main using the following code line:
System.out.println(myMethod(n, null));
I have tried his version and it prints the triangle on it's side but the largest line only prints once instead of twice. I have spent all day trying to alter his to add in a duplicate line in the middle and am starting to think it isn't possible.
Any help would be GREATLY appreciated. I am at a complete standstill with this.
Change the method signature to public static void myMethod(int n, boolean reversed) where reversed is initialized to false but flips to true when you print n asterisks. Inside the method, reverse your logic if reversed is true.
You basically just need to print out the current row, then do the recursive call, then print the row again. That way, you get the stack buildup on the way up, and then again on the way down.
Here is an example that uses 2 parameters, one being the max length and the other being the iterator for the recursion.
// bootstrap method to start the recursion
public static void myMethod(int length)
{
myMethod(length, length);
}
public static void myMethod(int length, int i)
{
if (i > 0)
{
int rowLength = length - i + 1;
printRow(rowLength, '*');
myMethod(length, i - 1);
printRow(rowLength, '*');
}
}
public static void printRow(int length, char symbol)
{
for (int i = 0; i < length; i++)
System.out.print(symbol);
System.out.println();
}
Because the output counts up (not *down to zero), you must pass in the number of asterisks to print and the maximum number, so the terminating condition can be established.
Further, the pseudo code for your method is:
if n > max return (terminating condition)
print n asterisks
recursively call with n + 1
print n asterisks
A great deal of code simplification can be achieved if you pass in not the current length to print, but the String of asterisks, so your (private) recursive method could be simply:
private static void myMethod(int n, String s) {
if (s.length() < n) return;
System.out.println(s);
myMethod(n, s + "*");
System.out.println(s);
}
And your public method, which sets up the initial conditions, is then:
public static void myMethod(int n) {
myMethod(n, "*");
}
IMHO an elegant implementation with good code density.