I am learning how to calculate the time and space complexity recently. I know how to calculate the basic one. However, when it involves some pre-built method, I got confused. For example, the code below uses the indexOf() method in the String class, how do I calculate? Thanks!
class Solution {
public String longestCommonPrefix(String[] strs) {
String prefix = strs[0];
for(int i = 1; i < strs.length; i ++){
while(strs[i].indexOf(prefix) != 0){
prefix = prefix.substring(0,prefix.length()-1);
}
}return prefix;
}
}
As written in comments, this existing answer suggests:
There is nothing like time complexity of a program. We calculate time complexity for algorithms or, in the context of programming, for individual (atomic) functions.
But to answer the implicit "how to go about this in an interview?":
In the above example, understand that there are the explicit loops. If you focus on that, you can estimate how many times the inner loop body gets executed
From there, you could "mentally" inline that library call
Leading to: you would suggest to inspect the source code of the library methods to understand its runtime cost
Related
I have an array list with some names inside it (first and last names). What I have to do is go through each "first name" and see how many times a character (which the user specifies) shows up at the end of every first name in the array list, and then print out the number of times that character showed up.
public int countFirstName(char c) {
int i = 0;
for (Name n : list) {
if (n.getFirstName().length() - 1 == c) {
i++;
}
}
return i;
}
That is the code I have. The problem is that the counter (i) doesn't add 1 even if there is a character that matches the end of the first name.
You're comparing the index of last character in the string to the required character, instead of the last character itself, which you can access with charAt:
String firstName = n.getFirstName()
if (firstName.charAt(firstName.length() - 1) == c) {
i++;
}
When you're setting out learning to code, there is a great value in using pencil and paper, or describing your algorithm ahead of time, in the language you think in. Most people that learn a foreign language start out by assembling a sentence in their native language, translating it to foreign, then speaking the foreign. Few, if any, learners of a foreign language are able to think in it natively
Coding is no different; all your life you've been speaking English and thinking in it. Now you're aiming to learn a different pattern of thinking, syntax, key words. This task will go a lot easier if you:
work out in high level natural language what you want to do first
write down the steps in clear and simple language, like a recipe
don't try to do too much at once
Had I been a tutor marking your program, id have been looking for something like this:
//method to count the number of list entries ending with a particular character
public int countFirstNamesEndingWith(char lookFor) {
//declare a variable to hold the count
int cnt = 0;
//iterate the list
for (Name n : list) {
//get the first name
String fn = n.getFirstName();
//get the last char of it
char lc = fn.charAt(fn.length() - 1);
//compare
if (lc == lookFor) {
cnt++;
}
}
return cnt;
}
Taking the bullet points in turn:
The comments serve as a high level description of what must be done. We write them aLL first, before even writing a single line of code. My course penalised uncommented code, and writing them first was a handy way of getting the requirement out of the way (they're a chore, right? Not always, but..) but also it is really easy to write a logic algorithm in high level language, then translate the steps into the language learning. I definitely think if you'd taken this approach you wouldn't have made the error you did, as it would have been clear that the code you wrote didn't implement the algorithm you'd have described earlier
Don't try to do too much in one line. Yes, I'm sure plenty of coders think it looks cool, or trick, or shows off what impressive coding smarts they have to pack a good 10 line algorithm into a single line of code that uses some obscure language features but one day it's highly likely that someone else is going to have to come along to maintain that code, improve it or change part of what it does - at that moment it's no longer cool, and it was never really a smart thing to do
Aominee, in their comment, actually gives us something like an example of this:
return (int)list.stream().filter(e -> e.charAt.length()-1)==c).count();
It's a one line implementation of a solution to your problem. Cool huh? Well, it has a bug* (for a start) but it's not the main thrust of my argument. At a more basic level: have you got any idea what it's doing? can you look at it and in 2 seconds tell me how it works?
It's quite an advanced language feature, it's trick for sure, but it might be a very poor solution because it's hard to understand, hard to maintain as a result, and does a lot while looking like a little- it only really makes sense if you're well versed in the language. This one line bundles up a facility that loops over your list, a feature that effectively has a tiny sub method that is called for every item in the list, and whose job is to calculate if the name ends with the sought char
It p's a brilliant feature, a cute example and it surely has its place in production java, but it's place is probably not here, in your learning exercise
Similarly, I'd go as far to say that this line of yours:
if (n.getFirstName().length() - 1 == c) {
Is approaching "doing too much" - I say this because it's where your logic broke down; you didn't write enough code to effectively implement the algorithm. You'd actually have to write even more code to implement this way:
if (n.getFirstName().charAt(n.getFirstName().length() - 1) == c) {
This is a right eyeful to load into your brain and understand. The accepted answer broke it down a bit by first getting the name into a temporary variable. That's a sensible optimisation. I broke it out another step by getting the last char into a temp variable. In a production system I probably wouldn't go that far, but this is your learning phase - try to minimise the number of operations each of your lines does. It will aid your understanding of your own code a great deal
If you do ever get a penchant for writing as much code as possible in as few chars, look at some code golf games here on the stack exchange network; the game is to abuse as many language features as possible to make really short, trick code.. pretty much every winner stands as a testament to condense that should never, ever be put into a production system maintained by normal coders who value their sanity
*the bug is it doesn't get the first name out of the Name object
I have a .toUpperCase() happening in a tight loop and have profiled and shown it is impacting application performance. Annoying thing is it's being called on strings already in capital letters. I'm considering just dropping the call to .toUpperCase() but this makes my code less safe for future use.
This level of Java performance optimization is past my experience thus far. Is there any way to do a pre-compilation, set an annotation, etc. to skip the call to toUpperCase on already upper case strings?
What you need to do if you can is call .toUpperCase() on the string once, and store it so that when you go through the loop you won't have to do it each time.
I don't believe there is a pre-compilation situation - you can't know in advance what data the code will be handling. If anyone can correct me on this, it's be pretty awesome.
If you post some example code, I'd be able to help a lot more - it really depends on what kind of access you have to the data before you get to the loop. If your loop is actually doing the data access (e.g., reading from a file) and you don't have control over where those files come from, your hands are a lot more tied than if the data is hardcoded.
Any many cases there's an easy answer, but in some, there's not much you can do.
You can try equalsIgnoreCase, too. It doesn't make a new string.
No you cannot do this using an annotation or pre-compilation because your input is given during the runtime and the annotation and pre-compilation are compile time constructions.
If you would have known the input in advance then you could simply convert it to uppercase before running the application, i.e. before you compile your application.
Note that there are many ways to optimize string handling but without more information we cannot give you any tailor made solution.
You can write a simple function isUpperCase(String) and call it before calling toUpperCase():
if (!isUpperCase(s)) {
s = s.toUpperCase()
}
It might be not significantly faster but at least this way less garbage will be created. If a majority of the strings in your input are already upper case this is very valid optimization.
isUpperCase function will look roughly like this:
boolean isUpperCase(String s) {
for (int i = 0; i < s.length; i++) {
if (Character.isLowerCase(s.charAt(i)) {
return false;
}
}
return true;
}
you need to do an if statement that conditions those letters out of it. the ideas good just have a condition. Then work with ascii codes so convert it using (int) then find the ascii numbers for uppercase which i have no idea what it is, and then continue saying if ascii whatever is true then ignore this section or if its for specific letters in a line then ignore it for charAt(i)
sorry its a rough explanation
I am Android developer and not new to Java but I have some questions about best practices for performace. Ill give some examples from my code so you can decide.
String concatenation
url = "http://www.myserver." + domain + "/rss.php?"
+ rawType + rawCathegory + rawSubCathegory + rawLocality
+ rawRadius + rawKeyword + rawPriceFrom + rawPriceto;
As far as I know, this would create 11 string objects before my url variable is created, right?
Ive been taught to use StringBuilder, but my question is, whats the minimum amount of strings to concat to make it efficient? I think it wouldnt make much sense to use it concat two strings, right?
Local variables
Sometimes I try to "chain" method calls like so
FilterData.getInstance(context).getFilter(position).setActivated(isActivated);
to naively avoid variable allocation, but is it any faster than this?
FilterData filterData = FilterData.getInstance(context);
Filter filter = filterData.getFilter(position);
filter.setActivated(isActivated);
I believe it should as I save myself a local variable, but it becomes unreadable if the method names are long, etc.
Loops
http://developer.android.com/training/articles/perf-tips.html says that enhanced for loops is 3x faster than the regular for loop, well that great and its easier to write anyways, but, what if I need the index? As far as I know, in enhaced for loop I need to keep track of it myself, like this
int index = 0;
for(Object obj : objects) {
// do stuff
index++;
}
Is this still faster than the regular loop?
for(int i = 0; i < objects.size(); i++) {
// do stuff
}
I think that enhanced for loop maybe does optimisations about that limit, so maybe if the size() got optimized to this
int size = objects.size();
for(int i = 0; i < size; i++) {
// do stuff
}
How would that stand?
Thanks, I know this might be nitpicking and not make that much of a difference, but Ill rather learn such common tasks the right way.
Strings:
Unless there's a loop involved, the compiler is clever enough to do the concatenation for you in the best way.
When you're looping, use StringBuilder or Buffer.
Local Variables:
The two examples you give are identical. The memory still needs to be allocated even if you never give it a name.
Loops:
Depending on the type of loop, using enhanced loops can give a massive or negligible improvement, it's best to read up on the one you're using.
I have a Double that I want to knock the extra digits after the decimal place off of (I'm not too concerned about accuracy but feel free to mention it in your answer) prior to conversion into a String.
I was wondering whether it would be better to cast to an int or to use a DecimalFormat and call format(..) . Also, is it then more efficient to specify String.valueOf() or leave it as it is and let the compiler figure it out?
Sorry if I sound a bit ignorant, I'm genuinely curious to learn more of the technical details.
For reference, i'm drawing text to and android canvas:
c.drawText("FPS: " + String.valueOf((int)lastFps), xPos, yPos, paint);
Casting will probably be more efficient. This is implemented as native code while using a method will have to go through the java code. Also it's much more readable.
For the string.valueof, I expect the performance to be strictly the same. I find it more readable to just do "string" + intValue than "string" + String.valueof(intValue)
I made a program that used System.nanoTime() to calculate the execution time of these two methods:
public static void cast() {
for (int i=0; i<1000000; i++) {
int x= (int)Math.random();
}
}
public static void format() {
for (int i=0; i< 1000000; i++) {
DecimalFormat df = new DecimalFormat("#");
df.format(Math.random());
}
}
Here are the respective results:
80984944
6048075593
Granted my tests probably aren't perfect examples. I'm just using math.random(), which generates a number that will always cast to 0, which might affect results. However, these results do make sense - casting should be cheap, since it likely doesn't operate on the bits at all - the JVM just treats the bits differently.
Edit: If I pull out the instantiation of the formatter for the second example, the program runs in 3155165182ns. If I multiply the random numbers by Integer.MAX_VALUE in both cases (with the instantiation pulled out), the results are: 82100170 and 4174558079. Looks like casting is the way to go.
This is a job for Math.floor().
Generally speaking, function/method calls come at the cost of performance overhead. My vote is that typecasting would be faster, but as #Zefiryn suggested, the best way is to create a loop and do each action a multitude of times and measure the performance with a timer.
I'm not sure about the efficiency of either, but here's a third option that could be interesting to compare:
String.valueOf(doubleValue).substring(0, endInt)
which would give a set number of characters rather than decimals/numbers, and would skip the typecasting but make two function calls instead.
EDIT: Was too curious so I tried running each option:
integerNumberFormat.format(number)
String.valueOf(doubleValue).substring(0, endInt)
String.valueOf((int)doubleValue)
10^6 cycles with the results being ~800 ms, ~300 ms and ~40 ms, respectively. I guess my results won't be immediately translatable to your situation but they could give a hint that the last one is indeed, as the previous posters suggested, the fastest one.
This question already has answers here:
Is there a performance difference between a for loop and a for-each loop?
(16 answers)
Closed 7 years ago.
(A question for those who know well the JVM compilation and optimization tricks... :-)
Is there any of the "for" and "foreach" patterns clearly superior to the other?
Consider the following two examples:
public void forLoop(String[] text)
{
if (text != null)
{
for (int i=0; i<text.length; i++)
{
// Do something with text[i]
}
}
}
public void foreachLoop(String[] text)
{
if (text != null)
{
for (String s : text)
{
// Do something with s, exactly as with text[i]
}
}
}
Is forLoop faster or slower than foreachLoop?
Assuming that in both cases the text array did not need any do sanity checks, is there a clear winner or still too close to make a call?
EDIT: As noted in some of the answers, the performance should be identical for arrays, whereas the "foreach" pattern could be slightly better for Abstract Data Types like a List. See also this answer which discusses the subject.
From section 14.14.2 of the JLS:
Otherwise, the Expression necessarily has an array type, T[]. Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced for statement. Then the meaning of the enhanced for statement is given by the following basic for statement:
T[] a = Expression;
L1: L2: ... Lm:
for (int i = 0; i < a.length; i++) {
VariableModifiersopt Type Identifier = a[i];
Statement
}
In other words, I'd expect them to end up being compiled to the same code.
There's definitely a clear winner: the enhanced for loop is more readable. That should be your primary concern - you should only even consider micro-optimizing this sort of thing when you've proved that the most readable form doesn't perform as well as you want.
You can write your own simple test, which measure the execution time.
long start = System.currentTimeMillis();
forLoop(text);
long end = System.currentTimeMillis();
long result = end - start;
result is execution time.
Since you are using an array type, the performance difference wouldn't matter. They would end up giving the same performance after going through the optimization funnel.
But if you are using ADTs like List, then the forEachLoop is obviously the best choice compared to multiple get(i) calls.
You should choose the option which is more readable almost every time, unless you know you have a performance issue.
In this case, I would say they are guaranteed to be the same.
The only difference is you extra check for text.length which is likely to be slower, rather than faster.
I would also ensure text is never null statically. e.g. using an #NotNull annotation. Its better to catch these issues at compile/build time (and it would be faster)
There is no performance penalty for using the for-each loop, even for arrays. In fact, it may offer a slight performance advantage over an ordinary for loop in some circumstances, as it computes the limit of the array index only once. For details follow this post.