What language would you use for the job? Sure, you spend all day coding in Java, but you also work on enterprise software that runs on app servers, parses XML, connects to relational databases, and does other typical enterprisey stuff. You design complicated class hierarchies and testing frameworks. Your dependencies are all injected, control all inverted. Your frameworks and APIs are legendary.
But here you are...it's 10 am and you have a whiteboard, some markers, and some simple string manipulation to do (when was the last time you had to manipulate strings anyway?). You're nervous, the clock's ticking, and now that you've got the O(N) solution in your head, you need to express it in working, readable code... and fast!
So you break out your best Java, and suddenly the language presents you with a number of distracting questions. Do you return an array of Strings or a String of words? Do you use a List or an array (and possibly arraycopy)? Since it won't technically run without one, do you bother defining a class? Is the method public, private, protected, or default? You know static is evil, but should you just make it static for the sake of the interview?
Here's how I envision a typical* interview for an entry-level position...
Java Jimmy
JJ: "OK, I think I have a working solution in my head, I'll just write it up as a method...I'll have it take a String and return a String, and I'll call it reverseWords."
public String reverseWords(String words) {
JJ: "Oh, wait, is it ok that this isn't in a class? I know it won't run outside of a class, so maybe I should play it safe."
class StringUtil {
public String reverseWords(String words) {
Me: "Hey, don't worry about that, a simple method is fine."
JJ: "And I can skip main?"
Me: "Yes, that's fine, this is just a utility method somewhere."
JJ: "OK, I should probably make it static, even though static is evil."
public static String reverseWords(String words) {
JJ: "Do you care about being super efficient? I could use String concatenation or StringBuilder."
Me: "Whatever you prefer."
JJ: "Ok, since using StringBuilder.reverse is probably cheating, I'll use Strings and an index."
public static String reverseWords(String words) {
String reverse = "";
for (int i = words.length()-1; i>=0; i--) {
reverse += words.charAt(i);
}
// now reverse words...
JJ: "Should I use StringTokenizer or regular expressions?"
Me: "Whatever you prefer."
JJ: "Hm, OK, StringTokenizer is pretty easy, so I'll use that. Do you want me to write the import statement?"
Me: "No, that's fine."
JJ: "Great."
String result = "";
StringTokenizer st = new StringTokenizer(reverse);
while (st.hasMoreTokens()) {
String word = st.nextToken();
for (int i = word.length()-1; i>=0; i--) {
result += word.charAt(i);
}
if (st.hasMoreTokens()) {
result += " ";
}
}
return result;
}
Me: "Great, now how does it perform?"
JJ: "Oh, well jeez, Strings are immutable, and I'm using string concatenation, so I should probably use StringBuilder...I'd never actually write it this way in production."
Me: "Sure, go for it."
public static String reverseWords(String words) {
String reverse = new StringBuilder(words).reverse()
.toString();
// now reverse words...
StringBuilder result = new StringBuilder();
StringTokenizer st = new StringTokenizer(
reverse.toString());
while (st.hasMoreTokens()) {
String word = st.nextToken();
for (int i = word.length()-1; i>=0; i--) {
result.append(word.charAt(i));
}
if (st.hasMoreTokens()) {
result.append(" ");
}
}
return result.toString();
}
JJ: "How's that?"
Me: "OK, great, now that you're warmed up, let's get to the main question."
JJ (inner monologue): "Holy crap, I only have 25 minutes left!"
Peter Python
PP: "OK, I'll define a simple method and use Python lists freely."
def reverse_words(words):
result = []
words = words[::-1]
for word in words.split():
result.append(word[::-1])
return ' '.join(result)
Me: "Great, can you make it even shorter?"
PP: "Oh! Of course!"
Me: "And how does it perform?"
def reverse_words(words):
return ' '.join(words.split()[::-1])
PP: "O(N), assuming that reverse, split, and join are all O(N), and why wouldn't they be?"
Me: "Nice work."
Rebecca Ruby
RR: "Oh fun! This'll be easy to code up in Ruby, is that ok?"
Me: "Sure, whatever you prefer."
RR: "OK, let's see, I want to reverse the words, split them, reverse each item, and then join them again."
def reverse_words(words)
words.reverse.split.map{|w| w.reverse}.join(' ')
end
RR: "I think I'm done. I hope I did it right. I just used some pretty basic ruby."
Me: "Wow, that was fast. What's the runtime?"
RR: "Assuming that reverse, split, and map are O(N) (and why shouldn't they be), this is O(N)."
Here are a few other things you'll have an easier time doing on your interview with Python or Ruby:
- Easily work with typical interview datatypes like strings, numbers, and lists.
- Slice and dice collections and strings
- Read to and from files
- Dynamically grow or shrink lists (it's amazing how often you actually need this in an interview)
- Create and manipulate hashtables (also comes up a lot in interviews)
- Generate test data
- Iterate over your solution and profile how long it takes for various datasets
- Just run your program. You don't need to compile it, you don't need "public static void main", you don't need classes, and you don't need to explain how you're using static even though you know it's a Bad Idea. And you don't need to choose between complicated command-line classpaths and big IDEs.