public String starString(int n){
int m = (int)Math.pow(2,n);
String str="";
str = starString(m-1,str);
return str;
}
private String starString(int n, String str){
String temp ="";
if (n<0) {
try{
throw new IllegalArgumentException();
}
catch(IllegalArgumentException ex){
}
}
else {
temp+=("*");
starString(n-1,str);
}
return temp;
}
Can someone please explain to me why this code returns a single asterisk even if its called by a value greater than n >= 0?
I debugged and noticed that after throwing the exception it recurses again and all the asterisks get chopped to "". I've tried it many times. Its also required that you should throw the IllegalArgumentException if n < 0.
In Java strings are immuntable, hence you need to assign a new value to temp (and pass temp as the parameter):
temp = starString(n-1, temp);
Additionally you'd need to assign str to temp, otherwise each recursion would just return a single asterisk:
String temp = str;
A much simpler, cleaner (and correct) version of your recursive method would look like this:
private String starString(int n){
String temp = "*";
//only recurse as long as n > 0, i.e. the last invocation would be made with n = 0
if (n > 0){
temp += starString(n-1);
}
return temp;
}
Note that you don't even need to pass the string as a parameter. Also note that recursion is overkill here, using a loop would make much nore sense. Also note that string concatenation is costly and gets slow quickly for higher values of n (due to immutable string instances being created over and over again). In that case you'd better use StringBuilder:
private String starString(int n){
StringBuilder s = new StringBuilder();
for( int i = 0; i <= n; i++ ) {
s.append("*");
}
return s.toString();
}
On my machine a loop version using string concatenation takes around 12 seconds for n = 100000 whereas the StringBuilder version takes 0.007 seconds.
Your code invokes every recursion, stores a local temp, returns this and it is never used.
Related
I'm trying to concatenate a string with itself and remove all capital letters from the resultant string.
Here is my code:
public String removeCapitals(String A) {
StringBuilder B = new StringBuilder(A+A);
int n = B.length();
for(int i=0; i<n; i++){
if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
B.deleteCharAt(i);
}
}
return B.toString();
}
I'm getting Exception saying:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6
at java.lang.AbstractStringBuilder.charAt(AbstractStringBuilder.java:237)
at java.lang.StringBuilder.charAt(StringBuilder.java:76)
at Solution.removeCapitals(Solution.java:10)
at Main.main(Main.java:190)
Can someone help me to understand the issue.
If at least one removal succeeds, at some point your code will attempt to access an invalid index that exceeds the length of a StringBuilder.
It happens because the variable n remain unchanged. You should change the condition to be bound to the current size of StringBuilder and decrement the index at each removal, or iterate backwards (as shown in another answer).
Also condition B.charAt(i)>='A' && B.charAt(i)<='Z' can be replaced with:
Character.isUpperCase(b.charAt(i))
Which is more descriptive.
That's how it might look like:
public static String removeCapitals(String a) {
StringBuilder b = new StringBuilder(a + a);
for (int i = 0; i < b.length(); i++) {
if (Character.isUpperCase(b.charAt(i))) {
b.deleteCharAt(i); // which can be combined with the next line `b.deleteCharAt(i--);` - previous value of `i` would be used in the call `deleteCharAt()` and variable `i` will hold a value decremented by 1
i--;
}
}
return b.toString();
}
Method deleteCharAt() runs in a linear time, because it shifts all subsequent characters in the underlying array bytes. Each upper-case letter will trigger these shifts and in the worst case scenario, it would result in the quadratic overall time complexity O(n ^ 2).
You make your method more performant and much more concise without using loops and StringBuilder. This code will run in a linear time O(n).
public static String removeCapitals(String a) {
return a.replaceAll("\\p{Upper}", "").repeat(2);
}
When you delete a character you change the length of the StringBuilder. But n still has the original length. So you will eventually exceed the size of the StringBuilder. So start from the end and move backwards. That way, any deletions will come after (based on relative indices) the next position so the index will be within the modified StringBuilder size. In addition, deleting from the end is more efficient since there is less copying to do in the StringBuilder.
public String removeCapitals(String A) {
StringBuilder B = new StringBuilder(A+A);
int n = B.length();
for(int i=n-1; i>=0; i--){
if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
B.deleteCharAt(i);
}
}
return B.toString();
}
If just remove Capital characters from a string. Alternative solution just create another method replaceAll() + regex
private static String removeCapitals(String A){
if (!A.isEmpty() && !A.equals("")) {
String B = A + A;
String newStr = B.replaceAll("([A-Z])", "");
return newStr;
} else {
return null;
}
}
Shorter solution to your task.
String a = "ABcdEF";
String b = "";
for (int i = 0; i < a.length(); i++) {
if(a.toLowerCase().charAt(i) == a.charAt(i))
b+=a.charAt(i);
}
System.out.println(b);
By changing to .toUpperCase() you'll get rid of the lower case ones.
Good morning all,
Today is my first time trying to make a recursion method. Just when I thought it would work I got the error; missing return statement. This confuses me because it literally has a return value ( the total string from the Stringbuilder ) after n < 1
This is what I got:
import java.util.Scanner;
public class P5_4MethodRepeatString {
public void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("Enter a string followed by the times you want
it repeated:");
String input = sc.nextLine();
int count = sc.nextInt();
String total = repeat(input, count);
System.out.println(total);
}
public static String repeat(String str, int n) {
StringBuilder full = new StringBuilder();
if(n < 1) {return full.toString();}
repeat(str, n - 1);
for(int i = 0; i < n; i++){
full.append(str);
}
}
}
if(n < 1) {return full.toString();} but if n >= 1 you don't return anything. It should be return repeat(str, n - 1); but then you need to move the for... part
The immediate cause of your problem is that not all conditional flows in your repeat() method have a return value. But I am not sure if even making that change would result in working code. Consider the following refactor:
public void repeat(StringBuilder result, String str, int n) {
if (n == 0) return;
result.append(str);
repeat(result, str, n - 1);
return;
}
Here we are passing in a StringBuilder object which we want to contain our repeated string results. We also pass the string to be repeated, and the number of remaining turns. The base case occurs where there are no more turns, in which case we simply return from the recursive method. Otherwise, we add one copy of the string and make a recursive call.
Your original recursive attempt had the following for loop:
for (int i=0; i < n; i++) {
full.append(str);
}
This does not look recursive, and looping to repeatedly add the string defeats the point of doing recursion (though I would probably use a loop in real life if I had to do this).
I have here a code that would take a String called toRepeat and repeat it in the same line by n number of times. For example toRepeat = *, n= 3, result = ***
public class RepeatIt {
public static String repeatString(final Object toRepeat, final int n) {
int i = 0;
if (toRepeat instanceof String) {
while (i < n) {
toRepeat = toRepeat + toRepeat;
}
return toRepeat;
} else {
return "Not a string";
}
}
}
However I get an Error on the + sign between the 2 toRepeat which states bad operand types for binary operator +. If you know how I could fix this please tell me I would much appreciate it.
You can change
while (i < n){
toRepeat = toRepeat + toRepeat; // operations are not defined for type Object
}
return toRepeat;
to
String tr = (String)toRepeat; // cast to String
while (i < n){
tr = tr + tr; // valid on String
i++; // some condition to terminate
}
return tr;
Edit: As suggested by #oleg, using StringBuilder should be preferred over concatenating Strings in a loop.
Edit2: To increment one character at a time, you can do something like :
String tr = (String)toRepeat; // this would be *
String finalVal = "";
while (i < n){
final = finalVal + tr; // would add * for each iteration
i++;
}
return finalVal;
There are actually three errors here:
The first is the type Object of toRepeat (and it being final, i.e. you may not assign a new value): there is no + for Object. You can cast it to String as shown in the answer before.
Second: your loop does not terminate, because i stays 0.
Third: If you increment i (e.g. i += 1 in the loop). You will get ** after the first loop, **** after the second and 8 stars after the third loop.
I think that Apache lib could help in most cases. It contains StringUtils class with lots of useful method to work with String. This is one of them:
public class RepeatIt {
public static String repeatString(final Object toRepeat, final int n) {
return toRepeat instanceof String ? org.apache.commons.lang3.StringUtils.repeat((String)toRepeat, n) : "Not a string";
}
}
I've seen lots of posts about reversing a string with recursion, but I like to use my own style of coding to properly understand it. Anyway here is the code I have.
private static String reverse (String s){
String rev = "";
int index = s.length()-1;
if(index >= 0){
rev += s.charAt(index);
index--;
rev += reverse(rev);
}
return rev;
}
Basically index just keeps going for every single character when index is -1 the loop stops. it reads the last possible character of the string but there is an error in this line here.
rev += rev(str)
Here is iterative method
String dog = "dog";
String rev = "";
int index = dog.length()-1;
while(index >= 0){
rev+=dog.charAt(index);
index--;
}
out.println(rev);
I believe when the method calls itself you reset the value of the index. Maybe a better approach would be to have an overloaded method where the original call passes in the string to process and then the remaining calls call a method where you pass in both the string you are building along with the remaining part of the that is being processed.
The recursive step doesn't contain the mutated string. You need to pass the substring of the original string.
rev = reverse(s.substring(0,index));
(Posted answer on behalf of the OP).
It's fixed now. Thank you so much, I was indexing too late and passing in negative numbers.
private static String reverse (String s) {
int index = s.length();
index--;
String rev = "";
if(index >= 0){
rev += s.charAt(index);
rev = rev + reverse(s.substring(0,index));
}
return rev;
}
I'm trying to use recursion to find the reverse of a string, but I get a stackoverflowerror when I run my code. I'm new to recursion so I'm not sure what I need to do to fix it.
public static String reverse(String string) {
int index = 0;
if(string == null){
return " ";
}
else if(index < string.length()) {
char a;
a = string.charAt(index);
index += 1;
return a + reverse(string);
}
return " ";
}
This is not how recursion should work, because you are just passing the same string over and over again. You could use recursion, but there are two approaches for your problem.
Get the last character and call the method with a string that doesn't have the last character, like so:
public String reverse(final String string) {
if (string != null && !string.isEmpty()) {
final int length = string.length();
final char character = string.charAt(length - 1));
final String result = reverse(string.substring(0, length - 2));
if (result != null)
return String.valueOf(character) + result;
return String.valueOf(character);
}
return null;
}
I should not that I have not tested this, but the point is that I am changing the string passed and have a mechanism to detect when to quit calling my own method.
The second method is to do this without recursion, because you can accomplish this with some for loops and such. But for the sake of learning, check 1 :P
There are a number of problems. I've added some comments to try to help.
public static String reverse(String string) {
int index = 0;
if(string == null){
return " ";
}
/* This will always be true because index is always zero */
else if(index < string.length()) {
char a;
/* This gets the character at position zero */
a = string.charAt(index);
/* This increments zero by 1 */
index += 1;
/* This takes the character and then calls reverse again (the recursion.
The problem is that you are passing the full string in and so every time
you recurse, index will be zero again and the string will be exactly the same length.
So no exit criterion will ever be triggered.
As such this is an infinite recursion. */
return a + reverse(string);
}
return " ";
}
I would suggest considering the following:
On the last recursive call, i.e. when you start to "pop back" through each of the recursive calls, what is it that you expect to trigger this?
If you decide that on every recursive call you are going to shorten the string by removing the first character, then the last call would be an empty string.
On the other hand, if you decide that your last call will be that the index variable equals the string length, then you will want to consider passing in an extra parameter (the index) and increasing this by one on every recursive call.
The piece you seem to be missing is passing the index into your function. Also, you need to return the current character at the end when you recurse. I think you wanted something like
private static String reverse(String string, int index) {
if (string != null && index < string.length()) {
char a = string.charAt(index);
return reverse(string, index + 1) + a;
}
return "";
}
Then your method in the public interface can call that function with an initial index of 0 like
public static String reverse(String string) {
return reverse(string, 0);
}
Of course, in real code I would prefer StringBuilder and something like
public static String reverse(String string) {
StringBuilder sb = new StringBuilder(string);
return sb.reverse().toString();
}
You're initializing variables "index and a" each time the recursive method get called. Initialize all of the variable outside the method block.
Try this function..
public static String reverse(String str){
if(str.length()<=0||str.length()==1)
return str;
return reverse(str.substring(1))+str.charAt(0);
}