Skip to Content
Course content

106: Mock Coding Interview Walkthrough in Go

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

Alright, let's put you in the hot seat. Imagine we're in a technical interview. The interviewer hands you a problem: Group Anagrams. You're given an array of strings, and you need to group the ones that are anagrams of each other into separate lists. If you've got "eat", "tea", and "tan", "ate", "nat", "bat", you should end up with [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]].

I'm going to walk through how I'd actually solve this live, including the mistakes I'd likely make and how I'd pivot. This isn't about the "perfect" solution immediately; it's about the process of arriving there using Go's specific toolset.

The "First Instinct" Approach

My first thought is that if two words are anagrams, they'll be identical if I sort their characters alphabetically. So, the plan is simple: iterate through the strings, sort each one, and use that sorted version as a key in a map. The value will be a slice of all the original strings that match that sorted key.

func groupAnagrams(strs []string) [][]string {
    groups := make(map[string][]string)

    for _, s := range strs {
        // I'll sort the string here...
        sortedS := sortString(s) 
        groups[sortedS] = append(groups[sortedS], s)
    }

    // Then I just need to flatten the map values into a slice of slices
    var result [][]string
    for _, group := range groups {
        result = append(result, group)
    }
    return result
}

Now, here is where I actually have to write that sortString helper. In Go, strings are immutable. I can't just call a sort method on a string. I have to convert it to a slice first.

Hitting the Map Key Wall

I might try to be clever here and use a slice of integers (a frequency count of letters) as the map key, since that's often faster than sorting. Let's see what happens if I try that:

func groupAnagrams(strs []string) [][]string {
    groups := make(map[[]int][]string) // Wait...
    // ... logic here
}

If I try to run this, the compiler will scream at me: invalid map key type []int. Right. I forgot for a second that in Go, slices are not "comparable." You can't use them as map keys because the language doesn't have a built-in way to determine if two slices are equal without iterating through them. This is a classic Go gotcha. If I want a frequency array as a key, I'd have to convert that array into a string or use a fixed-size array (like [26]int), because arrays are comparable.

Turning Sorted Slices into Keys

Let's stick to the sorting approach for a moment because it's more intuitive during an interview. To make sortString work, I have to convert the string to a []rune (to handle potential Unicode, though for basic anagrams []byte is faster), sort that slice, and then cast it back to a string so it can actually be a map key.

import (
    "sort"
)

func sortString(s string) string {
    r := []rune(s)
    sort.Slice(r, func(i, j int) bool {
        return r[i] < r[j]
    })
    return string(r)
}

Now the logic holds up. I'm taking the input, transforming it into a "canonical form" (the sorted string), and using that as the bucket ID in my map. It's clean, it's readable, and it leverages Go's map and slice dynamics effectively.

Polishing for Performance

If the interviewer asks, "Can we do better than O(N * K log K)?" (where N is the number of strings and K is the max length), I'd point back to that frequency array idea. Since we're usually dealing with lowercase English letters, a [26]int array is a perfect key.

Unlike a slice, a fixed-size array is a value type in Go. This means map[[26]int][]string is perfectly legal. I don't have to sort anything; I just count the letters.

func groupAnagrams(strs []string) [][]string {
    groups := make(map[[26]int][]string)

    for _, s := range strs {
        var count [26]int
        for _, char := range s {
            count[char-'a']++
        }
        groups[count] = append(groups[count], s)
    }

    result := make([][]string, 0, len(groups))
    for _, group := range groups {
        result = append(result, group)
    }
    return result
}

I love this version more. It's O(N * K). By swapping a slice for a fixed-size array, I bypassed the "comparable" limitation of Go maps and improved the time complexity. That's the kind of pivot that makes an interviewer realize you actually know the language internals, not just the syntax.




📋 Practical Task

Implement a "Unique Word Grouping" Tool

Build a function that takes a slice of phrases and groups them based on the set of unique words they contain, regardless of the order of the words or how many times a word is repeated. For example, "the cat and the dog" and "dog and cat the" should be grouped together because they both contain the unique set {the, cat, and, dog}.

Requirements:

  • Create a function groupPhrases(phrases []string) [][]string.
  • You must handle the "key" problem: since you can't use a slice or map as a map key, find a way to represent the unique sorted words of a phrase as a comparable Go type.
  • Ignore case sensitivity (e.g., "The" and "the" are the same word).
  • Ensure your final result is a slice of slices.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.