Skip to Content
Course content

166: Mock Coding Interview Walkthrough in Scala

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Alright, let's step into a mock interview scenario. Imagine the interviewer just handed you this prompt: "Given an array of strings, group the anagrams together."

Usually, when I'm in the hot seat, my first instinct is to get something working—anything—before I start polishing it into "idiomatic Scala." Let's start by sketching out the most basic way to solve this: iterate through the list, sort each word to create a key, and shove them into a map.

The "Just Make It Work" Phase

def groupAnagrams(strs: Array[String]): List[List[String]] = {
  val groups = scala.collection.mutable.Map[String, List[String]]()
  
  for (s <- strs) {
    val sortedS = s.sorted
    if (groups.contains(sortedS)) {
      groups(sortedS) = groups(sortedS) :+ s
    } else {
      groups(sortedS) = List(s)
    }
  }
  groups.values.toList
}

I'll be honest: if I wrote this in a real interview, a senior Scala dev would probably wince. It's too imperative. I'm using a mutable map, a for-loop, and—the real sin here—I'm using :+ to append to a List. Since Scala lists are linked lists, appending to the end is an $O(n)$ operation. If we have a huge group of anagrams, this is going to crawl.

Leaning Into the Functional Toolset

I want to get rid of that mutable map and the manual loop. This is exactly what groupBy was built for. If I can define a "key" for each element, Scala can handle the grouping logic internally. Let's see if we can condense this entire block into essentially one expression.

def groupAnagrams(strs: Array[String]): List[List[String]] = {
  strs.groupBy(_.sorted).values.toList.map(_.toList)
}

Wait, that's a lot cleaner. I'm taking the array, grouping it by the sorted version of each string, and then grabbing the values. I added .map(_.toList) at the end because groupBy returns values as Seq, and the prompt usually asks for a specific List return type. It's concise, but we should think about the performance. Sorting every single string takes $O(K \log K)$ where $K$ is the length of the longest string. For most interview cases, that's fine, but is there a way to avoid the sort?

Optimizing the Key Generation

If the strings are long, sorting is the bottleneck. I could instead create a frequency map of the characters (a "count" of each letter a-z) and use that as the key. Let's try to implement a helper function to create this character count string.

def getCharCount(s: String): String = {
  val counts = new Array[Int](26)
  for (c <- s) {
    counts(c - 'a') += 1
  }
  // Turn the array into a string like "1#0#2#..." to use as a map key
  counts.mkString("#")
}

def groupAnagramsOptimized(strs: Array[String]): List[List[String]] = {
  strs.groupBy(getCharCount).values.toList.map(_.toList)
}

Now we've shifted the complexity of the key generation from $O(K \log K)$ to $O(K)$. In a real interview, this is the moment where I'd stop and explain the trade-off: the sorted approach is more readable and shorter to write, while the character count approach is more performant for very long strings.

Final Polish for the Interviewer

To wrap this up, I'd make the method more generic. Why limit it to Array[String]? Let's make it take any Seq[String]. Also, I'll use a Map instead of a String for the key in the optimized version if I want to be strictly "type-safe," though a stringified array is often faster in practice.

The final version I'd present looks like this:

def groupAnagrams(strs: Seq[String]): List[List[String]] = {
  strs.groupBy { s =>
    s.sorted
  }.values.map(_.toList).toList
}

I've decided to stick with .sorted for the final "submitted" version because, unless the input strings are massive, the readability win is huge. In a coding interview, clarity beats micro-optimization unless the interviewer specifically asks for it.




📋 Practical Task

Implement a Frequency-Based Grouping for IP Addresses

In this exercise, you'll apply the groupBy pattern we just explored. You are given a list of IP addresses (as strings). You need to group these IP addresses by the number of unique octets they contain.

For example:

  • "192.168.1.1" has octets [192, 168, 1, 1]. The unique octets are {192, 168, 1}. The count is 3.
  • "10.0.0.10" has octets [10, 0, 0, 10]. The unique octets are {10, 0}. The count is 2.
  • "127.0.0.1" has octets [127, 0, 0, 1]. The unique octets are {127, 0, 1}. The count is 3.
The expected result for the list above would be a mapping where key 2 contains List("10.0.0.10") and key 3 contains List("192.168.1.1", "127.0.0.1").

Requirements:

  1. Write a function groupIPsByUniqueOctets(ips: Seq[String]): Map[Int, List[String]].
  2. Use the groupBy method.
  3. Inside the groupBy block, split the string by the dot (.), convert the resulting segments to a Set to find the unique values, and return the size of that set.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.