I needed to use this method, and after looking at the source code, I noticed a StringBuilder initialization which is not familar to me (I always use the no-argument constructor from StringBuilder, i.e. new StringBuilder()).
In the method:
StringBuilder sb = new StringBuilder(items.size() << 3);
From the JavaDoc:
java.lang.StringBuilder.StringBuilder(int capacity)
Constructs a string builder with no characters in it and an initial
capacity specified by the capacity argument.
Why a bit shift is needed here?
Source code:
/** Creates a backslash escaped string, joining all the items. */
public static String join(List<?> items, char separator) {
StringBuilder sb = new StringBuilder(items.size() << 3);
boolean first=true;
for (Object o : items) {
String item = o.toString();
if (first) {
first = false;
} else {
sb.append(separator);
}
for (int i=0; i<item.length(); i++) {
char ch = item.charAt(i);
if (ch=='\\' || ch == separator) {
sb.append('\\');
}
sb.append(ch);
}
}
return sb.toString();
}
Bitshift by 3 means multiplying by 2^3 which is 8. The author must have assumed that each item will take at most 8 characters in the resulting string. Therefore she or he initialized the StringBuilder with that capacity so it run efficiently. If the assumption is correct StringBuilder will not reallocate internal structures.
X << 3 means multiply X by 8. In your situation it means to allocate space for 8*list.size() characters. In general you should not care about the implementation details of a class that you are using
Is a modality to multiply by 8 items.size().
I think coder just speculate to initialCapacity to prevent (or reduce to minimum) StringBuilder() internal buffer reallocation.
Related
Given a string without spaces, the task is to remove duplicates from it.
Note: The original order of characters must be kept the same.
Example:
Input: S = "zvvo"
Output: "zvo"
Explanation: only keep the first
occurrence
I've written the following code, and I want to know its Space complexity.
public class Solution {
public String removeDups(String s) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i< s.length(); i++){
String ch = Character.toString(s.charAt(i));
if (sb.indexOf(ch) == -1)
sb.append(ch);
}
return sb.toString();
}
}
Space complexity of your solution is O(n) since it requires allocating in memory an instance of StringBuilder which would contain up to n characters, and transforming it into a String of the same length.
These memory costs are fine, but time complexity of your solution can be improved. Presented code runs in O(n^2) because method indexOf() performs iteration over the characters in your StringBuilder instance under the hood, and it's being invoked for every character in the given string.
To reduce the time complexity you can maintain a HashSet, and offer each character to the Set, if the character gets rejected it would mean that it was encountered before.
Here's how it might be implemented:
public String removeDups(String s) {
Set<Character> seen = new HashSet<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (seen.add(ch)) sb.append(ch);
}
return sb.toString();
}
Although we are using some additional memory, space complexity remains the same O(n) (because constants are not taken into consideration while evaluating the algorithm's complexity, 2*n and 3*n would result in O(n)). And time complexity would be linear O(n).
Given the string in the form of char array. Modify it the way that all the exclamation point symbols '!' are shifted to the start of the array, and all ohters are in the same order. Please write a method with a single argument of type char[]. Focus on either memory and time consumption of alghoritm.
Feedback that i've received: it was possible to use working with arrays instead of strings. Where can i find info about memory?
public static String formatString(char[] chars) {
StringBuilder exclamationSymbols = new StringBuilder();
StringBuilder otherSymbols = new StringBuilder();
for (char c : chars) {
if (c == '!') {
exclamationSymbols.append(c);
} else {
otherSymbols.append(c);
}
}
return (exclamationSymbols.toString() + otherSymbols.toString());
}
You can do this faster using a char[] than a StringBuilder because:
a StringBuilder is just a wrapper around a char[], so there's no way it can be faster. The indirection means it will be slower.
you know exactly how long the result will be, so you can allocate the minimum-sized char[] that you'll need. With a StringBuilder, you can pre-size it, but with two StringBuilders you can't exactly, so you either have to over-allocate the length (e.g. make both the same length as chars) or rely on StringBuilder resizing itself internally (which will be slower than not; and it uses moer memory).
My idea would be to use two integer pointers to point to the next position that you'll write a char to in the string: one starts at the start of the array, the other starts at the end; as you work your way through the input, the two pointers will move closer together.
Once you've processed the entire input, the portion of the result array corresponding to the "end pointer" will be backwards, so reverse it.
You can do it like this:
char[] newChars = new char[chars.length];
int left = 0;
int right = chars.length;
for (char c : chars) {
if (c == '!') {
newChars[left++] = c;
} else {
newChars[--right] = c;
}
}
// Reverse the "otherSymbols".
for (int i = right, j = newChars.length - 1; i < j; ++i, --j) {
char tmp = newChars[i];
newChars[i] = newChars[j];
newChars[j] = tmp;
}
return new String(newChars);
Ideone demo
I have a task which is to create a memory efficient method that takes a String consisting of numbers and removes any beginning zeros.
For instance "001112" becomes "1112".
public static String hej (String v)
{
StringBuilder h = new StringBuilder(v);
while(true)
{
if (h.charAt(0) == '0')
h.deleteCharAt(0);
else
break;
}
return h.toString();
}
This is my solution. Of course it does the work, but my question is, is it memory efficient to use the StringBuilder or is it more efficient to use the String itself and for instance v.substring()? Cant find too much information about what is more efficient. If anyone has links to some documentation, please share them.
Cheers
Using the String.substring(int) method will be the least memory used
public static String hej(String input)
{
int i;
for(i = 0; i < input.length(); i++)
if(input.charAt(i) != '0')
break;
return input.substring(i);
}
Source code from String:
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
This calls the String(char[], int, int) constructor
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
Using a StringBuilder uses a bit of memory to create the StringBuilder for the size of the input, while using String.substring(int) will just use up as much memory as needed to represent the modified input
If your string were to have n amount of leading zeros, then using String instead of StringBuilder would consume n times more memory. You know that String creates a new space in memory everytime some char changes in it so StringBuilder is the way to go.
Keep in mind
Every string builder has a capacity. As long as the length of the
character sequence contained in the string builder does not exceed the
capacity, it is not necessary to allocate a new internal buffer. If
the internal buffer overflows, it is automatically made larger.
Oracle Docs
So
String
String is immutable ( once created can not be changed )object . The
object created as a String is stored in the Constant String Pool .
Every immutable object in Java is thread safe ,that implies String is
also thread safe . String can not be used by two threads
simultaneously. String once assigned can not be changed.
String demo = " hello " ; // The above object is stored in constant
string pool and its value can not be modified.
demo="Bye" ; //new "Bye" string is created in constant pool and
referenced by the demo variable // "hello" string still
exists in string constant pool and its value is not overrided but we
lost reference to the "hello"string
StringBuffer
StringBuffer is mutable means one can change the value of the object .
The object created through StringBuffer is stored in the heap .
StringBuffer has the same methods as the StringBuilder , but each
method in StringBuffer is synchronized that is StringBuffer is thread
safe .
Due to this it does not allow two threads to simultaneously access
the same method . Each method can be accessed by one thread at a time
.
But being thread safe has disadvantages too as the performance of the
StringBuffer hits due to thread safe property . Thus StringBuilder is
faster than the StringBuffer when calling the same methods of each
class.
StringBuffer value can be changed , it means it can be assigned to the
new value . Nowadays its a most common interview question ,the
differences between the above classes . String Buffer can be converted
to the string by using toString() method.
StringBuffer demo1 = new StringBuffer("Hello") ; // The above object
stored in heap and its value can be changed . demo1=new
StringBuffer("Bye"); // Above statement is right as it modifies the
value which is allowed in the StringBuffer
Java Hungry
Basically given an int, I need to generate a String with the same length containing only the specified character. Related question here, but it relates to C# and it does matter what's in the String.
This question, and my answer to it are why I am asking this one. I'm not sure what's the best way to go about it performance wise.
Example
Method signature:
String getPattern(int length, char character);
Usage:
//returns "zzzzzz"
getPattern(6, 'z');
What I've tried
String getPattern(int length, char character) {
String result = "";
for (int i = 0; i < length; i++) {
result += character;
}
return result;
}
Is this the best that I can do performance-wise?
You should use StringBuilder instead of concatenating chars this way. Use StringBuilder.append().
StringBuilder will give you better performance. The problem with concatenation the way you are doing is each time a new String (string is immutable) is created then the old string is copied, the new string is appended, and the old String is thrown away. It's a lot of extra work that over a period of type (like in a big for loop) will cause performance degradation.
StringUtils from commons-lang or Strings from guava are your friends. As already stated avoid String concatenations.
StringUtils.repeat("a", 3) // => "aaa"
Strings.repeat("hey", 3) // => "heyheyhey"
Use primitive char arrays & some standard util classes like Arrays
public class Test {
static String getPattern(int length, char character) {
char[] cArray = new char[length];
Arrays.fill(cArray, character);
// return Arrays.toString(cArray);
return new String(cArray);
}
static String buildPattern(int length, char character) {
StringBuilder sb= new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(character);
}
return sb.toString();
}
public static void main(String args[]){
long time = System.currentTimeMillis();
getPattern(10000000,'c');
time = System.currentTimeMillis() - time;
System.out.println(time); //prints 93
time = System.currentTimeMillis();
buildPattern(10000000,'c');
time = System.currentTimeMillis() - time;
System.out.println(time); //prints 188
}
}
EDIT Arrays.toString() gave lower performance since it eventually used a StringBuilder, but the new String did the magic.
Yikes, no.
A String is immutable in java; you can't change it. When you say:
result += character;
You're creating a new String every time.
You want to use a StringBuilder and append to it, then return a String with its toString() method.
I think it would be more efficient to do it like following,
String getPattern(int length, char character)
{
char[] list = new char[length];
for(int i =0;i<length;i++)
{
list[i] = character;
}
return new string(list);
}
Concatenating a String is never the most efficient, since String is immutable, for better performance you should use StringBuilder, and append()
String getPattern(int length, char character) {
StringBuilder sb= new StringBuilder(length)
for (int i = 0; i < length; i++) {
sb.append(character);
}
return sb.toString();
}
Performance-wise, I think you'd have better results creating a small String and concatenating (using StringBuilder of course) until you reach the request size: concatenating/appending "zzz" to "zzz" performs probably betters than concatenating 'z' three times (well, maybe not for such small numbers, but when you reach 100 or so chars, doing ten concatenations of 'z' followed by ten concatenations of "zzzzzzzzzz" is probably better than 100 concatenatinos of 'z').
Also, because you ask about GWT, results will vary a lot between DevMode (pure Java) and "production mode" (running in JS in the browser), and is likely to vary depending on the browser.
The only way to really know is to benchmark, everything else is pure speculation.
And possibly use deferred binding to use the most performing variant in each browser (that's exactly how StringBuilder is emulated in GWT).
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);