I have a code to test a string of characters to see if they are in palindrome form. I get an error at on the last line saying Stringbuilder cannot be converted to String. I don't understand if I am building a string, how is that not a string. Also, part of the assignment was to create our own stack class. Mine is called MyStack, but I am not sure I am calling it anywhere except when I make a new stack. How do I call MyStack instead of the library stack?
public boolean isPalindrome(String line) throws StackException {
MyStack Stack = new MyStack();
// initialize loop counters
int i = 0;
int n = line.length();
/* Push all char to a_stack */
while (i < line.length()){
char ch = line.charAt(i);
Stack.push(ch);
i++;
}
StringBuilder result = new StringBuilder();
while (!Stack.empty()){
result.append(Stack.pop());
}
result.toString();
return inputString.equalsIgnoreCase(result);
}
Convert StringBuilder to String
return inputString.equalsIgnoreCase(result.toString());
You may try this:
return inputString.equalsIgnoreCase(result.toString());
instead of
return inputString.equalsIgnoreCase(result);
ie, you have to convert StringBuilder to String
Since String.equalsIgnoreCase(String) takes a String, and not a StringBuilder, you need to convert the StringBuilder to a String for that equality check, also I think you meant line not inputString
return line.equalsIgnoreCase(result.toString());
Related
I am trying to write a program for these instructions:
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty String as valid palindrome.
https://leetcode.com/problems/valid-palindrome/
For some reason, the .reverse() in the last line doesn't reverse it. I've tried debugging by adding print statements and I see that the string DOES reverse earlier on. What is going on here? Please guide me!
public static boolean isPalindrome(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (Character.isLetter(s.charAt(i))) {
sb.append(s.charAt(i));
}
}
String x = sb.reverse().toString();
System.out.println(x);
if (sb.length() == 0)
return true;
else
return sb.toString().equals(x);
}
The problem is that reverse() changes the StringBuilder itself. So you are comparing the reverse, with the reverse again. Instead change your method to:
String x = sb.toString();
return sb.reverse().toString().equals(x);
Which will compare the StringBuilder before reversing, with the reversed StringBuilder. Note that the if(sb.length == 0) is not necessary, as if it is empty, sb.reverse().toString().equals(x) will still return true.
Also your search is case sensitive, when the problem statement says that it should match regardless of case. Change where you append to:
if (Character.isLetter(s.charAt(i))) {
sb.append(Character.toLowerCase(s.charAt(i)));
}
Also you can take advantage of replaceAll and toLowerCase() to shorten your method to:
public static boolean pali(String s) {
String copy = s.toLowerCase().replaceAll("[^a-z]", "");
return new StringBuilder(copy).reverse().toString().equals(copy);
}
Because after first invocation of sb.reverse() sb has changed it state.
I'm currently trying to loop through a String and identity a specific character within that string then add a specific character following on from the originally identified character.
For example using the string: aaaabbbcbbcbb
And the character I want to identify being: c
So every time a c is detected a following c will be added to the string and the loop will continue.
Thus aaaabbbcbbcbb will become aaaabbbccbbccbb.
I've been trying to make use of indexOf(),substring and charAt() but I'm currently either overriding other characters with a c or only detecting one c.
I know you've asked for a loop, but won't something as simple as a replace suffice?
String inputString = "aaaabbbcbbcbb";
String charToDouble = "c";
String result = inputString.replace(charToDouble, charToDouble+charToDouble);
// or `charToDouble+charToDouble` could be `charToDouble.repeat(2)` in JDK 11+
Try it online.
If you insist on using a loop however:
String inputString = "aaaabbbcbbcbb";
char charToDouble = 'c';
String result = "";
for(char c : inputString.toCharArray()){
result += c;
if(c == charToDouble){
result += c;
}
}
Try it online.
Iterate over all the characters. Add each one to a StringBuilder. If it matches the character you're looking for then add it again.
final String test = "aaaabbbcbbcbb";
final char searchChar = 'c';
final StringBuilder builder = new StringBuilder();
for (final char c : test.toCharArray())
{
builder.append(c);
if (c == searchChar)
{
builder.append(c);
}
}
System.out.println(builder.toString());
Output
aaaabbbccbbccbb
You probably are trying to modify a String in java. Strings in Java are immutable and cannot be changed like one might do in c++.
You can use StringBuilder to insert characters. eg:
StringBuilder builder = new StringBuilder("acb");
builder.insert(1, 'c');
The previous answer suggesting String.replace is the best solution, but if you need to do it some other way (e.g. for an exercise), then here's a 'modern' solution:
public static void main(String[] args) {
final String inputString = "aaaabbbcbbcbb";
final int charToDouble = 'c'; // A Unicode codepoint
final String result = inputString.codePoints()
.flatMap(c -> c == charToDouble ? IntStream.of(c, c) : IntStream.of(c))
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
assert result.equals("aaaabbbccbbccbb");
}
This looks at each character in turn (in an IntStream). It doubles the character if it matches the target. It then accumulates each character in a StringBuilder.
A micro-optimization can be made to pre-allocate the StringBuilder's capacity. We know the maximum possible size of the new string is double the old string, so StringBuilder::new can be replaced by () -> new StringBuilder(inputString.length()*2). However, I'm not sure if it's worth the sacrifice in readability.
I am trying to write a program in Java that decompresses a compressed RLE statement using recursion, but I am continuously getting stack overflow errors and I do not know why.
Here is what I wrote thus far:
public class StringRec
{
public static void main (String args[]){
System.out.println(decompress("wed4d"));
}
//Version 0.1
public static String decompress(String compressedText)
{ String cText = compressedText;
StringBuffer newString = new StringBuffer();
int i = 0;
if (cText==""){return newString.toString();}
if(!cText.isEmpty()){
if(Character.isLetter(cText.charAt(i))){
newString.append(cText.charAt(i));
cText = cText.substring(1,cText.length());
return decompress(cText);
//remove first letter, return new modified string with removed first letter to decompress.
}
if(Character.isDigit(cText.charAt(i))){
int c = cText.charAt(i)-'0';
if (c==0){
cText = cText.substring(2,cText.length());}
return decompress(cText);
//delete c and the letter after it and send new modified string to decompress.
}
}else {
newString.append(cText.charAt(i+1));
int c = cText.charAt(i);
c--;
String num = ""+c;
cText = cText.replaceFirst(num, Character.toString(cText.charAt(i)));
return decompress(cText);
//appends character after number to newString, decrements the number and returns
//the new modified string to decompress with the first number decremented by one
}
return newString.toString();
}
}
My base case for the recursion is an empty string, if the string starts with a letter that letter is added to the stringbuffer newString only once and that first letter of the original string is deleted from the string sequence and the new string is passed to decompress; if it starts with a number that is zero then the first two chars of the string are deleted and the new string is passed to decompress.
If it's a number greater than 0[else] then the letter in front of it is added to the stringbuffer newString and the number is decremented and replaces the number in the beginning of the string and passes the new string [with the original first char number - 1] to decompress.
I believe the infinite recursion is occurring because of this:
int c = cText.charAt(i);
c--;
String num = ""+c;
cText = cText.replaceFirst(num, Character.toString(cText.charAt(i)));
If the character is 1, then c will be 65, the ASCII value of the character '1'. Then num will be set to the string "64", and if there's no "64" in your string, the method will keep calling itself with the same string over and over. Declaring c as a char should fix that. Plus, note that replaceFirst says to search for a pattern that matches the first argument, and replace it with the second. You may have this backwards. Also, see my comment above about newString.
EDIT:To answer your comment: Using a StringBuffer is OK. What you cannot do is have each decompress create a new StringBuffer, because then each time decompress is called a new StringBuffer will be created, which isn't what you want. If decompress takes a StringBuffer newString parameter, and each time decompress calls itself it passes newString as a parameter, then every decompress call will point to the same StringBuffer, since it's a reference to an object.
The other approach that I think you hinted at was that since decompress returns a String, then every time decompress calls itself it can use the function result (right now your code is just throwing it away), and perhaps concatenate that function result with something else and return the new string. I think you can make this approach work, but I haven't studied it thoroughly.
I'm utterly boggled as to why charAt() works in some scenarios but not others. I am doing exercises while learning Java and one of them was to take a string, and return it in reverse order.
My working code:
public String reverseString(String tempStr){
int initialindex = tempStr.length()-1;
int reverseindex = 0;
char tmp;
char[] array = new char[tempStr.length()];
for(int tempchar : array){
tmp = tempStr.charAt(initialindex);
array[reverseindex] = tmp;
initialindex--;
reverseindex++;
}
String returnstr = new String(array);
return returnstr;
}
The problem I ran into is using the following for statement prints gibberish:
for(int tempchar : array){
array[reverseindex] = tempStr.charAt(initialindex);
initialindex--;
reverseindex++;
}
There were perhaps a dozen different variants of using while loops, standard for loops and a few other versions of code that were ugly and didn't work. Why did my making a char tmp field, putting the inspected characrer in said field, and then using said field to enter the data into an array work?
Also, why am I unable to just return the string using return array.toString();?
Edit: I'm using the latest Eclipse I downloaded today, switched from netbeans.
I copied your code into my editor and it performed fine using either version, with tmp field or without. You must have made some other error using the other method.
Java doesn't support pretty .toString() for arrays; any object which does not override toString will produce the hashCode of the object rather than the contents/fields of the object, and arrays are no exception here. Whilst it might seem sensible for character arrays, the same operation on an int array would produce nonsense; See the difference between Arrays.toString() and String.valueOf(array). In this case, you probably want to use the String.valueOf method.
The array.toString() return string representation of the object. You need to use char[] constructor of String new String(array) to create String from the char[].
As a hint to get you started: if you want to convert a char array into a String use the String constructor that takes a char array.
Update: I see you already did that in your edit. Does it work as expected now?
Your loop looks a little bit weird since you never use your loop variable. you could try this:
char[] initialArray = initialStr.toCharArray();
char[] array = new char[tempStr.length()];
for(int srcIndex = 0, destIndex = array.length-1; destIndex >= 0; srcIndex++, destIndex--) {
array[destIndex] = initialArray[srcIndex];
}
public String reverse(String str)
{
if(str == null)
{
return null;
}
byte[] byteArray= str.getBytes();
int arrayLastIndex = byteArray.length -1 ;
for(int i=0 ; i < byteArray.lenght/2: i++)
{
byte temp = byteArray[i];
byteArray[i] = byteArray[arrayLastIndex -i ]
byteArray[arrayLastIndex - i] = temp;
}
return new String(byteArray);
}
This question already has answers here:
Simple way to repeat a string
(32 answers)
Closed 4 years ago.
I did check the other questions; this question has its focus on solving this particular question the most efficient way.
Sometimes you want to create a new string with a specified length, and with a default character filling the entire string.
ie, it would be cool if you could do new String(10, '*') and create a new String from there, with a length of 10 characters all having a *.
Because such a constructor does not exist, and you cannot extend from String, you have either to create a wrapper class or a method to do this for you.
At this moment I am using this:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
char[] array = new char[length];
int pos = 0;
while (pos < length) {
array[pos] = charToFill;
pos++;
}
return new String(array);
}
It still lacks any checking (ie, when length is 0 it will not work). I am constructing the array first because I believe it is faster than using string concatination or using a StringBuffer to do so.
Anyone else has a better sollution?
Apache Commons Lang (probably useful enough to be on the classpath of any non-trivial project) has StringUtils.repeat():
String filled = StringUtils.repeat("*", 10);
Easy!
Simply use the StringUtils class from apache commons lang project. You have a leftPad method:
StringUtils.leftPad("foobar", 10, '*'); // Returns "****foobar"
No need to do the loop, and using just standard Java library classes:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
if (length > 0) {
char[] array = new char[length];
Arrays.fill(array, charToFill);
return new String(array);
}
return "";
}
As you can see, I also added suitable code for the length == 0 case.
Some possible solutions.
This creates a String with length-times '0' filled and replaces then the '0' with the charToFill (old school).
String s = String.format("%0" + length + "d", 0).replace('0', charToFill);
This creates a List containing length-times Strings with charToFill and then joining the List into a String.
String s = String.join("", Collections.nCopies(length, String.valueOf(charToFill)));
This creates a unlimited java8 Stream with Strings with charToFill, limits the output to length and collects the results with a String joiner (new school).
String s = Stream.generate(() -> String.valueOf(charToFill)).limit(length).collect(Collectors.joining());
In Java 11, you have repeat:
String s = " ";
s = s.repeat(1);
(Although at the time of writing still subject to change)
char[] chars = new char[10];
Arrays.fill(chars, '*');
String text = new String(chars);
To improve performance you could have a single predefined sting if you know the max length like:
String template = "####################################";
And then simply perform a substring once you know the length.
Solution using Google Guava
String filled = Strings.repeat("*", 10);
public static String fillString(int count,char c) {
StringBuilder sb = new StringBuilder( count );
for( int i=0; i<count; i++ ) {
sb.append( c );
}
return sb.toString();
}
What is wrong?
using Dollar is simple:
String filled = $("=").repeat(10).toString(); // produces "=========="
Solution using Google Guava, since I prefer it to Apache Commons-Lang:
/**
* Returns a String with exactly the given length composed entirely of
* the given character.
* #param length the length of the returned string
* #param c the character to fill the String with
*/
public static String stringOfLength(final int length, final char c)
{
return Strings.padEnd("", length, c);
}
The above is fine. Do you mind if I ask you a question - Is this causing you a problem? It seams to me you are optimizing before you know if you need to.
Now for my over engineered solution. In many (thou not all) cases you can use CharSequence instead of a String.
public class OneCharSequence implements CharSequence {
private final char value;
private final int length;
public OneCharSequence(final char value, final int length) {
this.value = value;
this.length = length;
}
public char charAt(int index) {
if(index < length) return value;
throw new IndexOutOfBoundsException();
}
public int length() {
return length;
}
public CharSequence subSequence(int start, int end) {
return new OneCharSequence(value, (end-start));
}
public String toString() {
char[] array = new char[length];
Arrays.fill(array, value);
return new String(array);
}
}
One extra note: it seems that all public ways of creating a new String instance involves necessarily the copy of whatever buffer you are working with, be it a char[], a StringBuffer or a StringBuilder. From the String javadoc (and is repeated in the respective toString methods from the other classes):
The contents of the character array are copied; subsequent modification of
the character array does not affect
the newly created string.
So you'll end up having a possibly big memory copy operation after the "fast filling" of the array. The only solution that may avoid this issue is the one from #mlk, if you can manage working directly with the proposed CharSequence implementation (what may be the case).
PS: I would post this as a comment but I don't have enough reputation to do that yet.
Try this Using the substring(int start, int end); method
String myLongString = "abcdefghij";
if (myLongString .length() >= 10)
String shortStr = myLongString.substring(0, 5)+ "...";
this will return abcde.
Mi solution :
pw = "1321";
if (pw.length() < 16){
for(int x = pw.length() ; x < 16 ; x++){
pw += "*";
}
}
The output :
1321************
Try this jobber
String stringy =null;
byte[] buffer = new byte[100000];
for (int i = 0; i < buffer.length; i++) {
buffer[i] =0;
}
stringy =StringUtils.toAsciiString(buffer);