StringBuilder deleteCharAt() function " String index out of range : 6 " - java

Code and Error
Error 2
hey Guys see the Image and help me out to sort out this issue
It is the first code and it runs perfectly but when i use the same approach in the blow code it have some error
" For error detail open image link "
String str = "Samaarth";
StringBuilder sb = new StringBuilder(str);
sb.deleteCharAt(3);
System.out.println(sb.toString());
This is where the error start and the error is because of DeleteCharAt() function but in the above code this function works perfectly but here it is not
IDK why so please help me out to sort our this issue
String str= "aaabccddd";
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < str.length() -1; i++) {
if (sb.charAt(i) == sb.charAt(i + 1)) {
sb.deleteCharAt(i);
//sb.deleteCharAt(i+1);
}
}
System.out.println(sb.toString());

Samarath, you both modify the string and advance the counter.
This is wrong. Consider the string "aaaa"
This is what your code does:
i = 0: you find the duplicate, remove it. The string becomes "aaa".
Then you advance the position: i becomes 1
i = 1: the string is "a|aa" (the vertical bar shows the position).
You find the duplicate at position 1. You kill it, the string
becomes "aa", but you advance the position one again: i becomes 2
At this step the for loop ends and your string is "aa".
Instead the algorithm should use while loop: "while there are duplicates, kill them!"
String str= "aaabccddd";
StringBuilder sb = new StringBuilder(str);
int i = 0;
while (i < sb.length()-1) {
if (sb.charAt(i) == sb.charAt(i + 1)) {
sb.deleteCharAt(i);
// Do not increment -- kill all duplicates
} else {
// Either not a duplicate, or all duplicated killed
// Advance one char
i++;
}
}
System.out.println(sb.toString());
The output is abcd.
If you are inclined to use for loop, then iterate in the reverse order:
String str= "aaabccddd";
StringBuilder sb = new StringBuilder(str);
for (int i = sb.length()-1; i > 0; i--) {
if (sb.charAt(i) == sb.charAt(i - 1)) {
// Note charAt(i - 1) - we compare with the preceding character
sb.deleteCharAt(i);
// The string squeezes by one char, but the decremented position
// will follow
}
}
System.out.println(sb.toString());
The output is abcd

The problem is you are using for loop and you are actually changing/mutating StringBuilder instance at the same time, so the .length() will not be fixed and eventually you will try to reach non-existing index in your for loop and exception will be thrown.
EDIT:
Add these two lines inside your for loop if statement, just before you invoke deleteCharAt() method:
System.out.println("Value of i is: " + i);
System.out.println("StringBuilder length is: " + sb.length());
"i" represents index you are trying to delete, and sb.length() will display actual length of the StringBuilder.

Related

How do i reverse each character in a string?

class Solution {
public String reverseWords(String s) {
int count = 0;
int current = 0;
StringBuilder build = new StringBuilder();
for(int i = 0; i< s.length(); i++){
count++;
current = count;
if(s.charAt(i) == ' '){
while(current > 0){
build.append(s.charAt(current - 1));
current--;
}
build.append(s.charAt(i));
}
}
return build.toString();
}
}
I am having trouble understanding why this doesn't work. I went through the
entire code a couple of times but there seems to be an issue.
Input : "Let's take LeetCode contest"
my answer: " s'teL ekat s'teL edoCteeL ekat s'teL "
correct answer: "s'teL ekat edoCteeL tsetnoc"
whats going on?
There are several problems:
You set current to the current position, and then iterate down to 0 append characters. Instead of going down to 0, you iterate until the beginning of the last word. Alternative, iterate until the previous ' ' character.
You only append something after seeing a ' ' character. What will happen at the end of the sentences? As i goes over the letters in the last word, there will be no more ' ' characters, and so the last word will never get appended. To handle this case, you would need to add some logic after the for-loop to check if there is an unwritten word, and append it reversed.
A simpler approach is to take advantage of the StringBuilder's ability to insert characters at some position.
You could track the beginning position of the current word,
and as you iterate over the characters,
insert if it's not ' ',
or else append a ' ' and reset the insertion position.
StringBuilder build = new StringBuilder();
int current = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ' ') {
build.append(' ');
current = i + 1;
} else {
build.insert(current, c);
}
}
return build.toString();
Use a StringBuilder to reverse each word in your String :
String input = "Let's take LeetCode contest";
String[] split = input.split(" +");
StringBuilder output = new StringBuilder();
for (int i = 0; i < split.length; i++) {
output.append(new StringBuilder(split[i]).reverse());
if(i<input.length()-1)
output.append(" ");
}
System.out.println(output);
First, you skip over index 0. Put these lines at the end of your method to avoid this:
count++;
current = count;
You might need a variable to track where the current word began. For example, declare one along with count and current like this:
int wordStart = 0;
Then, when you finish processing a word, set wordStart to point to the first character of the next word. I would put that after the while loop, here:
build.append(s.charAt(i));
wordStart = count + 1;
You will also need to change this: while(current > 0){ to this: while(current >= wordStart)
Also: you don't need count. The variable i is the exact same thing.
You can use stream-api for your goal:
Stream.of(str.split(" "))
.map(s -> new StringBuilder(s).reverse().toString())
.reduce((s1, s2) -> s1 + " " + s2)
.orElse(null);
This is the easy way:
return Arrays.stream(s.split(" " ))
.map(StringBuilder::new)
.map(StringBuilder::reverse)
.map(StringBuilder::toString)
.collect(Collectors.joining(" "));

Performance (JAVA) ~ String concatenation in a loop with prepending and appending

I'm having performance issues. Does anyone have a faster/better solution for doing the following:
String main = "";
for (String proposition : propositions) {
if (main.length() == 0) {
main = proposition;
} else {
main = "|(" + proposition + "," + main + ")";
}
}
I know concat and stringbuilder are faster, but i don't see how i can use these methods. Because of the following line of code:
main = "|(" + proposition + "," + main + ")";
Thanks in advance!
So from what I can tell there are 3 problems here:
Values are primarily prepended to the string.
For each value a character is appended.
If only one value is present, nothing should be appended or prepended.
With 2 or more items, the 0th item is handled differently:
0:""
1:"A"
2:"|(B,A)"
3:"|(C,|(B,A))"
It can be made quicker by making a few changes:
Reverse the algorithm, this means the majority of the work involves appending, allowing you to use StringBuilders.
Count the number of closing )'s and append those after the loop is finished.
Special case for 0 or 1 items in the list.
With those changes the algorithm should be able to use a StringBuilder and be a lot quicker.
Attempt at an algorithm:
int length = propositions.size();
if (length == 0) {
main = "";
} else {
StringBuilder sb = new StringBuilder();
int nestingDepth = 0;
// Reverse loop, ignoring 0th element due to special case
for (int i = length - 1; i > 0; i--) {
sb.append("|(").append(propositions.get(i)).append(',');
nestingDepth++;
}
// Append last element due to special casing
sb.append(propositions.get(0));
for (int i = 0; i < nestingDepth; i++) {
sb.append(')');
}
main = sb.toString();
}
I believe this should produce the correct results, but it should give the right idea.
The problem is that you're prepending and appending to the string as you go. String and StringBuilder dont handle this well (and give quadratic performance). But you can use a dequeue which supports insertion at start and end to store all the pieces. Then finally you can join the bits in the dequeue.
ArrayDeque bits = new ArrayDeque();
for (String proposition : propositions) {
if (bits.size() == 0) {
bits.push(proposition);
} else {
// Add prefix
main.offerFirst("|(" + proposition + "," );
// Add suffix
main.push(")");
}
}
StringBuilder sb = new StringBuilder();
for( String s : bits) {
sb.append(s);
}
main = sb.toString();
Assuming this is an array of propositions, you could first sum the length of the String(s) in the array. Add 4 for your additional characters, and subtract 4 because you don't use those separators on the first element. That should be the perfect size for your output (this is optional, because StringBuilder is dynamically sized). Next, construct a StringBuilder. Add the first element. All subsequent elements follow the same pattern, so the loop is simplified with a traditional for. Something like,
int len = Stream.of(propositions).mapToInt(s -> s.length() + 4).sum() - 4;
StringBuilder sb = new StringBuilder(len); // <-- len is optional
sb.append(propositions[0]);
for (int i = 1; i < propositions.length; i++) {
sb.insert(0, ",").insert(0, propositions[i]).insert(0, "|(").append(")");
}
System.out.println(sb);

Java string get latest 4 char reverse loop

I cannot figure how to obtain latest 4 char of string before zeroes
String str = "41f1f3d1f10000000000000000000000000000000000"
I want: d1f1
I've tried to revert string string than do straight loop
public static boolean checklast4digit(String risposta) {
String crc = "";
risposta = reverseIt(risposta);
for (int i = 0; i < risposta.length(); i++) {
if (risposta.charAt(i) != '0') crc = Character.toString(risposta.charAt(i + 3)) + Character.toString(risposta.charAt(i + 2)) + Character.toString(risposta.charAt(i + 1)) + Character.toString(risposta.charAt(i));
}
Log.i("Crc letto: ", crc);
return true;
}
public static String reverseIt(String source) { //Inversione stringa
int i, len = source.length();
StringBuilder dest = new StringBuilder(len);
for (i = (len - 1); i >= 0; i--) {
dest.append(source.charAt(i));
}
return dest.toString();
}
Exception:
java.lang.StringIndexOutOfBoundsException
As mentioned in the comments, you are looping too far. If you want to access charAt(i+3) you should only loop until i < risposta.length() - 3
Also, you need to break out of your loop, once you have found your result:
for(int i=0 ;i < risposta.length() - 3 ;i++){
if(risposta.charAt(i) != '0') {
crc= Character.toString(risposta.charAt(i + 3)) + Character.toString(risposta.charAt(i+2)) + Character.toString(risposta.charAt(i+1)) + Character.toString(risposta.charAt(i));
break;
}
}
Note that this only gives you a result, if you have 4 non-zero characters before the zeros.
There are many ways to improve your code, one of which would be to just remove the trailing zeroes first, then reverse the remaining string and take the first 4 chars of it.
However, to point out errors in your code...
Take a look at the values you're using to get characters. While your loop is limited to i<risposta.length(), i+3 that you're using in the line below is not - it can go up to risposta.length()+2. If oyu want to fix the code, then change the loop condition to i+3<risposta.length().
It's not elegant and can be done better, but that would solve the immediate bug in your code.
Your IndexOutOfBoundsException is caused by:
risposta.charAt(i + 3)
risposta.charAt(i+2)
risposta.charAt(i+1)
If you take a look at your for loop:
for(int i=0 ; i < risposta.length(); i++){
}
You are iterating from index 0 to risposta.length() - 1. However because you are getting the char at i+3 when i is risposta.length() - 1 it tries to access the index risposta.length() + 2 which is out of bounds.
You ned to modify your loop so you only iterate up to risposta.length() - 3
Here you have a oneliner!
String a = new StringBuilder(new StringBuilder("41f1f3d1f10000000000000000000000000000000000".split("0")[0]).reverse().toString().substring(0, 4)).reverse().toString();
And the complete code looks like this:
package nl.testing.startingpoint;
public class Main {
public static void main(String args[]) {
String a = new StringBuilder(new StringBuilder("41f1f3d1f10000000000000000000000000000000000".split("0")[0]).reverse().toString().substring(0, 4)).reverse().toString();
System.out.println(a);
}
}
result: d1f1
Alternatively, you could strip the 0's with a replaceAll and then get the last 4 chars with a substring. That makes the code pretty simple:
public static void main(String[] args) {
String str = "41f1f3d1f10000000000000000000000000000000000";
str = str.replaceAll("0*$", "");
System.out.println(str.substring(str.length()-4));
}
First of all the StringBuilder has a reverse method, which you can use to revers a string. That would simplify the reversing quite a bit.
return new StringBuilder(source).reverse().toString();
and as the others pointed out your for loop probably causes the exception, as it iterates to long.
To remove all trailing zeros (as suggested by CptBartender) you can use regex.
risposta = risposta.replaceFirst("0+$");
Then you can reverse the string (as shown above) and get the first n characters using the substring method.
reversed.substring(0, Math.min(reversed.length(), 4));
Math.min() is used to ensure there is no error if there are less than 4 characters before the zeros.

In Java,how can the letters in strings be doubled?

I'm a beginner no matter how you look at it, so bear with me here. The project is about having a string in the code and then doubling every letter in it, while tripling the exclamation points. Nothing else is doubled. It's supposed to take something like this:
The quick brown fox jumps over the lazy dog 3 times!
...and turn it into this:
Tthhee qquuiicckk bbrroowwnn ffooxx jjuummppss oovveerr tthhee llaazzyy ddoogg 3 ttiimmeess!!!
This is the code I tried, though it prints in numbers and takes a bunch of loops to complete instead of one:
String s = "The quick brown fox jumps over the lazy dog 3 times!";
String output = "";
int i = 0;
while (i < s.length()) {
char c = s.charAt(i);
if (s.charAt(i) == '!') {
output += c + c + c;
i++;
}
if (Character.isLetter(c) == true) {
output += c + c;
i++;
} else {
i++;
}
System.out.println(output);
}
You really should use a StringBuilder, but char + char produces a char not a String (it does numeric addition). You probably want output += "" + c + c + c; since it will convert the chars to a String and then append them. (Likewise for the line output += c + c;)
A clean solution could look like this:
String s = "The quick brown fox jumps over the lazy dog 3 times!";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '!') {
sb.append(c).append(c).append(c);
} else if (Character.isLetter(c)) {
sb.append(c).append(c);
} else {
sb.append(c);
}
}
String output = sb.toString();
System.out.println(output);
The problems it fixes
Your code will skip a character after it encounters a '!'. You go into the first if, increment i correct, but then return to the rest of the code below, hit the next if, condition is false because ! is not a letter, so it goes in to else path and increments i a second time. You should ether use continue to prevent fall-through or use if .. else if .. else which enforces mutually exclusive flow as well.
A while loop is IMO more complicated to read than a for loop. You also don't have to increment i like 3 times. Once at the end of the while loop would be enough.
String concatenation in loops is best done with a StringBuilder. It can also append char without converting it to a number.
You forgot that you have to append c once when it's no special case.
You don't want to do System.out.println(output); inside the loop but afterwards. That's why you saw a lot more output lines than expected
formatting hiding issues like the one above
String s = "The quick brown fox jumps over the lazy dog 3 times!";
StringBuilder builder = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char temp = s.charAt(i);
builder.append(temp);
if (Character.isLetter(temp)) {
builder.append(temp);
} else if (temp == '!') {
builder.append(temp).append(temp);
}
}
System.out.println("Result: " + builder.toString());
You should convert the numbers back in characters first through a so called cast
like (char) output.
Try it and play around with it, learning and experimenting is the best thing about a beginning ;-)
Hope it helps.
Using a StringBuilder gives a short and clear solution :
String s = "The quick brown fox jumps over the lazy dog 3 times!";
StringBuilder sb = new StringBuilder();
for (int i=0 ; i<s.length() ; i++) {
String ch = s.charAt(i) + "";
sb.append(ch.matches("\\s") ? ch : ch + ch);
}
System.out.println(sb.toString());
Character is a number that represents the actual english character. Adding two characters will give you just a new number that number will represent some new character .
Use StringBuilder class for what you are doing.
This code worked fine for me...
String s = "The quick brown fox jumps over the lazy dog 3 times!";
String output = "";
int n = s.length();
for(int i = 0; i<n; i++){
String sub = s.substring(i, i+1);
output = output + sub + sub;
}
System.out.println(output);
Instead of printing the string what I think you are doing is printing the numbers asoociated with each character added together.
Add a "" into your concatenation, i.e. output+= "" + c + c;
But make sure to add the empty string before you add the characters otherwise it will add the characters together, giving you a number, and then converting it to a string.
Also, in your else statement you might want to add an output+= c line, otherwise it looks like you will lose your number 3 and your spaces.

Java - Grouping repeated chars in a String

(This is not homework)
We have some extra exercices we can do, and i have done some.
But i got stuck in this one...
I need to make a program that given the string "loool" prints "l:1:o:3:l:1".
I have tried a bunch of combinations but i keep getting the same problem:
- I cant make the last repeated letter to get print ( Because with my code the next char needs to be different for a print to occurr).
String str = "loool";
StringBuilder sb = new StringBuilder();
int count = 1;
char before;
before = str.charAt(0);
for (int i = 1;i < str.length();i++) {
if (str.charAt(i) == before) {
count++;
}
else {
sb.append(before + ":" + count);
before = str.charAt(i);
count = 1;
}
}
return sb.toString();
You need to add some logic after your loop has finished, in order to deal with this problem. This logic will probably be very similar to the some of the code that you're using in the else block.

Categories

Resources