While getting groceries, I saw this endcap for cotton candy-flavored energy drink. The “XBox controller as phone” pose is silly, but it also reminded me of a phone I’d wanted way back in the early 2000s: the Nokia N-Gage.
Released in 2003 (in the pre-smartphone era, back when mobile phones sported a lot of dedicated buttons), the N-Gage was a phone-meets-handheld gaming device.IGN summed it up best as “a bad console filled with bad games,” and it didn’t help that the speaker and microphone were mounted on its side. In order to use it as a phone, you’d have to hold it like this — a position that would come to be known as sidetalking:
Sidetalking looked silly, so soon there were sidetalking photos featuring people using the N-Gage while making silly faces…
…followed by people ditching the N-Gage altogether and opting to take sidetalking photos with any old electronic thing, turning it into a full-blown meme:
In case you’re wondering, I’m not really pining for the N-Gage anymore. My iPhone 13 Pro is a decent gaming phone, and on the Android side, I’ve got a Nubia Redmagic 6R that plays Genshin Impact rather nicely.
A couple of readers posted their solution in the comments, and I decided to take a closer look at them. I also decided to write my own JavaScript solution, which led me to refine my Python solution.
“CK”’s JavaScript solution
The first reader-submitted solution comes from “CK,” who submitted a JavaScript solution that uses sets:
// JavaScript
function findFirstNonRepeatingChar(chars) {
let uniqs = new Set();
let repeats = new Set();
for (let ch of chars) {
if (! uniqs.has(ch)) {
uniqs.add(ch);
} else {
repeats.add(ch);
}
}
for (let ch of uniqs) {
if (! repeats.has(ch)) {
return ch;
}
}
return null;
}
The one thing that all programming languages that implement a set data structure is that every element in a set must be unique — you can’t put more than one of a specific element inside a set. If you try to add an element to a set that already contains that element, the set will simply ignore the addition.
In mathematics, the order of elements inside a set doesn’t matter. When it comes to programming languages, it varies — JavaScript preserves insertion order (that is, the order of items in a set is the same as the order in which they were added to the set) while Python doesn’t.
CK’s solution uses two sets: uniqs and repeats. It steps through the input string character by character and does the following:
If uniqs does not contain the current character, it means that we haven’t seen it before. Add the current character to uniqs, the set of characters that might be unique.
If uniqs contains the current character, it means that we’ve seen it before. Add the current character to repeats, the set of repeated characters.
Once the function has completed the above, it steps through uniqs character by character, looking for the first character in uniqs that isn’t in repeats.
For a string of length n, the function performs the first for loop n times, and the second for loop some fraction of n times. So its computational complexity is O(n).
Thanks for the submission, CK!
Dan Budiac’s TypeScript solution
Dan Budiac provided the second submission, which he implemented in TypeScript:
// TypeScript
function firstNonRecurringCharacter(val: string): string | null {
// First, we split up the string into an
// array of individual characters.
const all = val.split('');
// Next, we de-dup the array so we’re not
// doing redundant work.
const unique = [...new Set(all)];
// Lastly, we return the first character in
// the array which occurs only once.
return unique.find((a) => {
const occurrences = all.filter((b) => a === b);
return occurrences.length === 1;
}) ?? null;
}
I really need to take up TypeScript, by the way.
Anyhow, Dan’s approach is similar to CK’s, except that it uses one set instead of two:
It creates an array, all, by splitting the input string into an array made up of its individual characters.
It then creates a set, unique, using the contents of all. Remember that sets ignore the addition of elements that they already contain, meaning that unique will contain only individual instances of the characters from all.
It then goes character by character through unique, checking the number of times each character appears in all.
For a string of length n:
Splitting the input string into the array all is O(n).
Creating the set unique from all is O(n).
The last part of the function features a find() method — O(n) — containing a filter() method — also O(n). That makes this operation O(n2). So the whole function is O(n2).
Thanks for writing in, Dan!
My JavaScript solution that doesn’t use sets
In the meantime, I’d been working on a JavaScript solution. I decided to play it safe and use JavaScript’s Map object, which holds key-value pairs and remembers the order in which they were inserted — in short, it’s like Python’s dictionaries, but with get() and set() syntax.
// JavaScript
function firstNonRecurringCharacter(text) {
// Maps preserve insertion order.
let characterRecord = new Map()
// This is pretty much the same as the first
// for loop in the Python version.
for (const character of text) {
if (characterRecord.has(character)) {
newCount = characterRecord.get(character) + 1
characterRecord.set(character, newCount)
} else {
characterRecord.set(character, 1)
}
}
// Just go through characterRecord item by item
// and return the first key-value pair
// for which the value of count is 1.
for (const [character, count] of characterRecord.entries()) {
if (count == 1) {
return character
}
}
return null
}
The final part of this function takes an approach that’s slightly different from the one in my original Python solution. It simply goes through characterRecord one key-value pair at a time and returns the key for the first pair it encounters whose value is 1.
It remains an O(n) solution.
My revised Python solution
If I revise my original Python solution to use the algorithm from my JavaScript solution, it becomes this:
# Python
def first_non_recurring_character(text):
character_record = {}
# Go through the text one character at a time
# keeping track of the number of times
# each character appears.
# In Python 3.7 and later, the order of items
# in a dictionary is the order in which they were added.
for character in text:
if character in character_record:
character_record[character] += 1
else:
character_record[character] = 1
# The first non-recurring character, if there is one,
# is the first item in the list of non-recurring characters.
for character in character_record:
if character_record[character] == 1:
return character
return None
Here’s an excerpt from the current version of my resume (yes, my resume’s under version control). Note the highlighted entry:
The entry is for Hyve, the startup and application that my StartupBus team built when I rode in 2019. Hyve was a service that let you create “burner” email addresses that relayed email to and from your real email address, allowing you to safely subscribe to services and avoid getting marketing spam or safely communicate with people whom you might not completely trust.
…but the real wins came a little bit afterward when I was interviewing for developer and developer relations jobs a couple of weeks afterward. StartupBus makes for a good story, and in a job interview, it’s the story that “sells” you.
After all, StartupBus is a hackathon where you’re challenged to come up with:
A startup business
and an application that supports that business
on a bus
in three days.
This intrigued the people who interviewed me, which led me to talk about the decisions that shaped the business, which in turn shaped the software. I detailed the challenges of writing business plans and software on a bus, a rumbling, rolling office space with spotty internet access, unreliable power, and the occasional engine breakdown. I also talked about dealing with the compressed timeframe and a few of the tricks we used to get around the limited time, which included getting help from our professional network, taking advantage of crowdsourcing services, and using our media contacts. My StartupBus story played a key part in convincing prospective employers that they wanted to hire me.
StartupBus Florida will depart Tampa, Florida on Wednesday, July 27 and make a 3-day trip with interesting stops and challenges along the way. It will arrive in Austin, Texas on the evening of Friday, July 29, where it will meet with teams from 6 other buses:
On Saturday, July 30, all the teams will assemble at a venue in Austin for the semifinals. Every team will pitch in front of a set of semifinals judges. By the end of the day, a handful of finalists will emerge (Hyve was one of six finalists in 2019).
Those finalists will then go on to the finals, which will take place on Sunday, July 31. They’ll pitch again (and if they’re smart, they’ll have spent the night before reworking their pitch and application) in front of the finals judges, who will select the winner and runners-up.
If you participate in StartupBus, you will come out of it a different person. You will pitch your startup at least a dozen times (and yes, everyone pitches — not just the marketing people, but the creatives and developers, too). You will work on product design. You will work on marketing. You will work on code. And you’ll do it all under far-from-ideal circumstances. StartupBus is a crash course in guerrilla entrepreneurship, and it’s an experience that will serve you well — especially during these economically upside-down times.
And you’d better believe that you’ll have stories to tell, and they’ll help you stand apart from the crowd.
Here’s the list of tech, entrepreneur, and nerd events for Tampa Bay and surrounding areas for the week of Monday, July 11 through Sunday, July 17, 2022.
Every week, with the assistance of a couple of Jupyter Notebooks that I put together, I compile this list for the Tampa Bay tech community.
As far as event types go, this list casts a rather wide net. It includes events that would be of interest to techies, nerds, and entrepreneurs. It includes (but isn’t limited to) events that fall under the category of:
Programming, DevOps, systems administration, and testing
Tech project management / agile processes
Video, board, and role-playing games
Book, philosophy, and discussion clubs
Tech, business, and entrepreneur networking events
Toastmasters (because nerds really need to up their presentation game)
Sci-fi, fantasy, and other genre fandoms
Anything I deem geeky
By “Tampa Bay and surrounding areas”, this list covers events that originate or are aimed at the area within 100 miles of the Port of Tampa. At the very least, that includes the cities of Tampa, St. Petersburg, and Clearwater, but as far north as Ocala, as far south as Fort Myers, and includes Orlando and its surrounding cities.
StartupBus 2022 will depart from Tampa Bay!
If you’re looking for an adventure, a chance to test your startup skills, and an experience that will make your résumé stand out, join me on StartupBus Florida, which departs Tampa Bay on July 27, when it sets course for Austin, Texas!
On this three-day journey, “buspreneurs” will form teams, create a business idea, build a software demo for that idea, and develop pitches for that idea. When they arrive in Austin, they’ll spend two days pitching their startups to a panel of judges.
I was a “buspreneur” on StartupBus Florida in 2019, the last time the event took place, and our team made it to the finals and got the runner-up position. This time, I’m a “conductor” — one of the coaches on the bus — and our team is here to help you rise to the challenge.
If you’d like to get this list in your email inbox every week, enter your email address below. You’ll only be emailed once a week, and the email will contain this list, plus links to any interesting news, upcoming events, and tech articles. Join the Tampa Bay Tech Events list and always be informed of what’s coming up in Tampa Bay!
Welcome back to How to solve coding interview questions! In this series of articles, I’ll walk you through the sort of questions that you might be asked in a coding interview and provide solutions in a couple of programming languages.
The first recurring character in the given string, if one exists, or
A null value like JavaScript’s or Kotlin’s null, Python’s None, or Swift’s nil.
I also provided solutions in Python, JavaScript, and Swift.
The follow-up challenge
Usually in a coding interview, if you succeed at the initial challenge, there’s usually a follow-up that is a more challenging variation on the theme. The “find the first recurring character” challenge is often followed up by looking for its opposite:
Write a Python function named first_nonrecurring_character() or a JavaScript function named firstNonRecurringCharacter() that takes a string and returns either:
The first NON-recurring character in the given string, if one exists, or
A null value like JavaScript’s or Kotlin’s null, Python’s None, or Swift’s nil.
Here are some example inputs for the function, along with what their corresponding outputs should be:
If you give the function this input…
…it should produce this output:
'aabbbXccdd'
'X'
'a🤣abbbXcc3dd'
'🤣'
‘aabbccdd'
null / None / nil
One solution
See if you can code it yourself, then scroll down for my solution.
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
Let’s consider the following example string:
"a🤣abbbXcc3dd"
The string is short, and I purposely made the first non-recurring character an emoji so that it would be easy to spot, so a glance is all you need to spot it.
One programmatic approach is to go through the string one character at a time and keep track of the number of times you’d encountered each character. For this example string, you’d end up with this:
Character
Number of times it appeared in the string
a
2
🤣
1
b
3
X
1
c
2
3
1
d
2
If you maintain the order in which the characters were encountered, the solution becomes either:
The first character that appears 1 time in the string, if one exists, or
A null value like JavaScript’s or Kotlin’s null, Python’s None, or Swift’s nil.
This was my first pass at a solution in Python:
# Python
def first_non_recurring_character(text):
character_record = {}
# Go through the text one character at a time
# keeping track of the number of times
# each character appears.
# In Python 3.7 and later, the order of items
# in a dictionary is the order in which they were added.
for character in text:
if character in character_record:
character_record[character] += 1
else:
character_record[character] = 1
# Now that we have a record of the number of times each character appears,
# create a list containing only those characters that have appeared once.
non_recurring_character_record = {k:v for (k, v) in character_record.items() if v == 1}
non_recurring_characters = list(non_recurring_character_record.keys())
# The first non-recurring character, if there is one,
# is the first item in the list of non-recurring characters.
if len(non_recurring_characters) == 0:
return None
else:
return non_recurring_characters[0]
What’s the Big O?
In the code above, there are 2 O(n) operations:
The for loop that builds a record of the number of times each character appears in the text, and
This list comprehension:
# Python
{k:v for (k, v) in character_record.items() if v == 1}
These operations take place one at a time, so the complexity of the code is O(2n). As far as computational complexity is concerned, constants don’t really matter; O(2n) is effectively the same as O(n).So its computational complexity is O(n).
An (unsuccessful) attempt to make the solution a little more time- and space-efficient
In its current form, the code builds a record of the number of times each character appears in the text — even those that appear more than once. Then, in the next step, it goes through that record to create a new record of the characters that appear only once.
I thought: “What if we eliminated that second step by building a record of only characters that appeared once?”
Here’s pseudocode that explains what I mean:
For each character in the text:
If the current character is already in the record:
Remove that character from the record
Otherwise:
Add that character to the record
At the end of the for loop, the character record contains only the characters that have appeared once.
Here’s my revised implementation:
# Python
def first_non_recurring_character(text):
character_record = {}
# Go through the text one character at a time
# but record ONLY those characters that appear once.
# In Python 3.7 and later, the order of items
# in a dictionary is the order in which they were added.
for character in text:
if character in character_record:
# We've seen this character before,
# so remove it from the record.
del character_record[character]
else:
# # We've never seen this character before,
# so add it to the record.
character_record[character] = 1
# character_record contains only those characters
# that appear ONCE in the string
non_recurring_characters = list(character_record.keys())
if len(non_recurring_characters) == 0:
return None
else:
return non_recurring_characters[0]
This solution seems like a good idea, but it has a big flaw! As one reader, Hans, astutely pointed out in a comment:
basically it tests if characters appear an odd number of times in a string. For example if a character appears a third time, it was removed the second time and consequently added again to character_record that third time.
This is true — by removing a character from character_record, it’s as if the character was never encountered. I’m going to treat this as a reminder to:
Not prematurely discard information, and
Write better tests!
So in the end, I should stick with my first solution. Good catch, Hans, and thanks for pointing out my mistake!