Funny and true:

Funny and true:
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.
In the previous article in this series, I presented you with a challenge to write a function that took a string as an argument and returned either:
null
, Python’s None
, or Swift’s nil
.I also provided solutions in Python, JavaScript, and Swift.
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:
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 |
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:
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]
In the code above, there are 2 O(n) operations:
for
loop that builds a record of the number of times each character appears in the text, and# 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).
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:
So in the end, I should stick with my first solution. Good catch, Hans, and thanks for pointing out my mistake!
If you’re looking for a startup job, you’re probably wondering “What warning signs should I look for?”. Fortunately, there’s a recent example to learn from: Fast.
Fast was a startup whose product was Fast Checkout, a one-click checkout system for ecommerce. Every step in the online checkout process increases the chance that the customer won’t complete the purchase. Reducing online purchases to a single click is such a big deal that Amazon patented the process in 1997, which has contributed to its runaway success. The patent expired in 2017, and with that came the competition to own the business of providing one-click checkout to everyone other than Amazon.
In 2021, having raised over $100 million in funding from investors that included Stripe, Fast announced that they were opening their east coast hub here in Tampa to great fanfare:
In a collapse that was incredibly (ahem) fast — even for an overhyped company with a burn rate fueled by stunt marketing — they closed down a mere 8 months later.
How do you avoid working at a startup like Fast? There aren’t any hard and (ahem) fast answers, but there are some lessons you can take from its failure and some warning signs you can look out for. Gergely Orosz of Pragmatic Engineer explains in his video, How to (not) choose a startup to join: lessons from Fast:
It’s true: 80% of a startup’s culture is its founder. Look at the founders’ history and be especially watchful for patterns of behavior or signs of the “there’s no there there” syndrome. One of Orosz’ former Uber coworkers tried to convince Orosz to join Fast, but after researching Fast cofounder Domm Holland’s checkered history, he decided to not join.
Ask questions like:
Earlier this week, I posted the first article in the How to solve coding interview questions series: Find the first recurring character in a string.
Here’s the challenge:
Write a Python function named
first_recurring_character()
or a JavaScript function namedfirstRecurringCharacter()
that takes a string and returns either:° The first recurring character in the given string, if one exists, or
° A null value like JavaScript’s or Kotlin’s
null
, Python’sNone
, or Swift’snil
.
Here’s the Swift version of my solution:
// Swift
func firstRecurringCharacter(text: String) -> String? {
var previouslyEncounteredCharacters = Set<Character>()
for character in text {
if previouslyEncounteredCharacters.contains(character) {
return String(character)
} else {
previouslyEncounteredCharacters.insert(character)
}
}
return nil
}
The Swift implementation differs from the Python and JavaScript versions due to Swift’s stricter typing
Set
requires you to specify the type of things that it will store. In this case, we want to store items of type Character
.for
loop in Swift, you get Character
items. That’s why previouslyEncounteredCharacters
stores Character
items and not String
items. Once the function detects the first recurring character, it converts that character into a string and returns that value.Here’s the list of tech, entrepreneur, and nerd events for Tampa Bay and surrounding areas for the week of Monday, July 4 through Sunday, July 10, 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:
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.
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.
Want to find out more?
Want to join the bus? Drop me a line!
Group | Event Name | Time |
---|---|---|
Young Professionals Networking JOIN in and Connect! | In person at Fords Garage St Pete | 11:00 AM |
Option Trading Strategies (Tampa Bay area) Meetup Group | Option Trading Strategies Meetup (Online) | 11:00 AM |
Entrepreneurs & Business Owners of Sarasota & Bradenton | Virtual Networking Lunch Monday | 11:30 AM |
Professional Business Networking with RGAnetwork.net | St. Pete Networking Lunch! Fords Garage! Monday’s | 11:30 AM |
Professional Business Networking with RGAnetwork.net | Virtual Networking Lunch | 11:30 AM |
Beginning Web Development | Weekly Learning Session | 6:00 PM |
Critical Hit Games | MTG: Commander Night | 6:00 PM |
Toastmasters Division G | Radiant Ridge Toastmasters | 6:00 PM |
Tampa Bay Tabletoppers | Monday Feast & Game Night | 6:00 PM |
Bradenton Photo Group | Camera Menus and Photography Tutorial | 6:30 PM |
Toastmasters District 48 | NO North Port Toastmasters .. Celebrate the 4th | 6:30 PM |
PWOs Unite! | Tampa PWOs Meetup | 7:00 PM |
Tampa Bay Gaming: RPG’s, Board Games & more! | Board Game Night at Armada Games | 7:00 PM |
Tampa – Sarasota – Venice Trivia & Quiz Meetup | Trivia Night – Motorworks Brewing Smartphone Trivia Game Show | 7:00 PM |
Light Study PRO – A Photography Workshop for Emerging Pros | Members as far back as 2008 can access their photos | 7:00 PM |
Toastmasters Division E | Lakeland (FL) Toastmasters Club #2262 | 7:00 PM |
Central Florida AD&D (1st ed.) Grognards Guild | World of Greyhawk: 1E One-Shots | 7:30 PM |
Tampa / St Pete Business Connections | Monday Virtual Business Introductions | 11:30 PM |
Toastmasters, Division D | ACE Advanced Toastmasters 3274480 | 6:00 PM |
Group | Event Name | Time |
---|---|---|
HOPE CUESTA | POWER GALS NETWORKING OF ST PETE | See event page |
Entrepreneur Collaborative Center | How to Sell When You Hate to Sell! | See event page |
Raysa Santiago Regional Vice President | Business Networking Event | See event page |
Bianca Baez with United Wealth Educators | Business Networking event | See event page |
RGANetwork.net | After hours Networking Mixer Cafe Delanie | See event page |
Doris Muller for NPI Westchase Chapter | Business Networking Event for Local Professionals | See event page |
Professional Business Networking with RGAnetwork.net | Virtual Networking Breakfast Thursday’s | 7:30 AM |
Professional Business Networking with RGAnetwork.net | Wesley Chapel/Lutz networking breakfast | 7:30 AM |
Pasco County Entrepreneurs & Business Owners All Welcome | Happy Hangar Early Bird Professionals Networking | 7:30 AM |
Wesley Chapel, Trinity, New Tampa, Business Professionals | Business Over Breakfast ~ Happy Hangar IN PERSON JOIN US! | 7:30 AM |
Young Professionals Networking JOIN in and Connect! | Tampa Young Professionals Virtual Networking Thursday Morning All WElCOME | 7:30 AM |
Business Networking Weekly Meeting for Local Professionals | Business Networking for Local Professionals | 8:00 AM |
TampaBayNetworkers | Suncoast Networkers | 8:30 AM |
Orlando Melrose Makers | In-Person: Makerspace Open Lab | 10:30 AM |
ManageEngine’s Cybersecurity Meetups | How to use preventive and defensive techniques for effective cybersecurity | 11:00 AM |
Business Game Changers Group | Clearwater Professional Networking Lunch | 11:00 AM |
Young Professionals Networking JOIN in and Connect! | The Founders Meeting where it all Began! JOIN us! Bring a guest and get a gift | 11:00 AM |
Block Co-op – Bitcoin Crypto Blockchain Orlando | Crypto Set-up Class -Limited to 5 Seats Only | 11:00 AM |
Tampa / St Pete Business Connections | Clearwater/Central Pinellas Networking Lunch | 11:00 AM |
Florida Startup: Idea to IPO | How to Cut Product Development Costs by up to 50%! | 11:00 AM |
Pasco County Entrepreneurs & Business Owners All Welcome | Wesley Chapel Professional Networking Lunch at Chuck Lager America’s Tavern | 11:30 AM |
SWAT Networking – Successful Women Aligning Together | SWAT Networking Parrish Luncheon | 11:30 AM |
Network Professionals Inc. of South Pinellas (NPI) | NPI Power Lunch – Exchange Qualified Business Referrals | 11:30 AM |
Tampa Bay Business Networking Meetings & Mixers | Brandon Networking Professionals Networking Lunch | 11:30 AM |
Ironhack Tampa – Tech Careers, Learning and Networking | Tech for Tides: How to Build a Surf App | 12:00 PM |
St Pete Networking | Professional Pitch Workshop + Public Speaking + Open Networking | 12:00 PM |
Orlando Cybersecurity Meetup | Synchronize IAM and HRMS for seamless employee life cycle management | 2:00 PM |
Free Video Production Classes – TV/Internet | YouTube Basics (ONLINE CLASS) – FREE for Hillsborough County Residents | 3:00 PM |
Tampa – Sarasota – Venice Trivia & Quiz Meetup | Trivia Night – Bunkers Bar of Sun City Center Smartphone Trivia Game Show | 5:00 PM |
Tampa / St Pete Business Connections | After hours Networking & Tasting, Food By 3’C’s Catering | 5:00 PM |
Pinellas Tech Network | Journey to the Cloud: Achieve Your Goals with App Modernization | 5:00 PM |
Tampa Bay Business Networking Happy Hour/Meetings/Meet Up | After Hours Networking Happy Hour! Food provided by 3C’s Catering | 6:00 PM |
Orlando Board Gaming Weekly Meetup | Central Florida Board Gaming at The Collective | 6:00 PM |
Summerfield Board/Card Game Night | Summerfield Tabletop/Board/Card Games | 6:00 PM |
Critical Hit Games | Warhammer Night | 6:00 PM |
Tampa Bay Gaming: RPG’s, Board Games & more! | D&D Adventurers League at Critical Hit Games | 6:00 PM |
Brandon and Seffner area AD&D Group | 1st ed AD&D Campaign. | 6:00 PM |
Toastmasters District 48 | GREY MATTERS: The Forum For Open Minds | 6:30 PM |
Bradenton Photo Group | Camera Basics | 6:30 PM |
Tampa Ybor Free Writing Group | Writing Meetup | 6:30 PM |
Tampa Bay Bitcoin | Bitcoin 101 | 7:00 PM |
Business Networking for Entrepreneurs of Color | Virtual Business Networking – Entrepreneurs of Color | 7:00 PM |
Tampa Hackerspace | Shopbot Safety and Usage (Members Only) | 7:00 PM |
PWOs Unite! | Tampa PWOs Meetup | 7:00 PM |
Cocktails and Convo: Book club for RomCom Lovers | Book talk: The Set Up by Lizzy Dent | 7:00 PM |
3D Printing Orlando | Cura Slicer Settings – Fundamentals | 7:00 PM |
Live streaming production and talent | Live streaming production and talent | 7:00 PM |
Tampa Bay Drupal User Group | Live Forum / Q&A | 7:00 PM |
Tampa Bay Coalition of Reason | Fossil Men: The Quest for the Oldest Skeleton and the Origins of Humankind | 7:00 PM |
Thinkful Tampa | Thinkful Webinar || UX/UI Design: Wireframes and Prototypes | 6:00 PM – 7:30 PM EDT |
Financial Secrets for Wealth Accumulation Personal/Business | HOW TO BECOME DEBT FREE INCLUDING MORTGAGE IN 10 YEARS OR LESS & BUILD WEALTH | 8:00 PM |
Emotional Intelligence in the 21st Century | Emotional Intelligence in the 21st Century | 8:00 PM |
Orlando Lady Developers Meetup | Coding Challenges with Vanessa | 8:00 PM |
Thinkful Tampa | Thinkful Webinar || Data Analytics: Tools of the Trade | 9:00 PM – 10:30 PM EDT |
Group | Event Name | Time |
---|---|---|
Florida Center for Creative Photography | Free – Adobe Lightroom Classic CC Class | 9:00 AM |
Toastmasters District 48 | Clearwater Sunday Speakers Toastmasters Club | 9:30 AM |
Board Games and Card Games in Sarasota & Bradenton | Games at Descent Into Gaming | 12:00 PM |
Thinkful Tampa | Thinkful Webinar || Enhancing Your Career With Mindfulness | 12:00 PM – 1:30 PM EDT |
Tampa Bay Gaming: RPG’s, Board Games & more! | D&D Adventurers League at Critical Hit Games | 2:00 PM |
Drunk’n Meeples West Pasco | Weekend Game Day | 2:00 PM |
Critical Hit Games | D&D Adventurers League | 2:00 PM |
Central Florida Computer Society | Please join us | 2:45 PM |
The Guild of Independent Game Developers | Lecture | 5:00 PM |
Tampa Hackerspace | Sew Awesome! (Textile Arts & Crafts) | 5:30 PM |
Lithia Dungeons & Dragons And Gaming Guild | 5E (ish) AD&D – Humble Beginnings Campaign (Trouble in Elm). | 6:00 PM |
Nerdbrew Events | Hidden Gems Night, Presented by A Duck! | 7:00 PM |
PWOs Unite! | Tampa PWOs Meetup | 7:00 PM |
Thinkful Tampa | Thinkful Webinar || UX/UI Design: Designing A UX Case Study | 6:00 PM – 7:30 PM EDT |
Solana – Tampa | Office Hours | 8:00 PM |
Nerd Night Out | NerdBrew Karaoke @ MacDinton’s! | 8:00 PM |
Thinkful Tampa | Thinkful Webinar || Intro To Data Analytics: Excel Basics | 9:00 PM – 10:30 PM EDT |
Let me know at joey@joeydevilla.com!
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!
If you had an application or script that uses Selenium and ChromeDriver to control or automate instances of Chrome or Chromium, it’s probably not working right now. Instead, you’re probably seeing error messages that look like this:
Message: unknown error: cannot determine loading status
from unknown error: unexpected command response
(Session info: chrome=103.0.5060.53)
Stacktrace:
0 chromedriver 0x000000010fb6f079 chromedriver + 4444281
1 chromedriver 0x000000010fafb403 chromedriver + 3970051
2 chromedriver 0x000000010f796038 chromedriver + 409656
...and on it goes...
The culprit is ChromeDriver 103, and I wrote about it a couple of days ago in a post titled Why your Selenium / ChromeDriver / Chrome setup stopped working.
ChromeDriver 103 — or more accurately, ChromeDriver 103.0.5060.53 — works specifically with Chrome/Chromium 103.0.5060.53. If you regularly update Chrome or Chromium and use ChromeDriverManager to keep ChromeDriver’s version in sync with the browser, you’ve probably updated to ChromeDriver 103.0.5060.53, which has a causes commands to ChromeDriver to sometimes fail.
Luckily, the bug has been fixed in ChromeDriver 104, which works specifically with Chrome 104. This means that if you update to Chrome and ChromeDriver 104, your Selenium / ChromeDriver / Chrome setup will work again.
The challenge is that Chrome 104 is still in beta. As I’m writing this, the Google Chrome Beta site is hosting an installer for Chrome 104, or more accurately, Chrome 104.0.5112.20. The application has the name Google Chrome Beta and is considered a separate app from Google Chrome. This means that you can have the current release and the beta version installed on your machine at the same time.
Once you’ve installed Chrome Beta, you just need to make your Selenium/ChromeDriver application or script use the appropriate version of ChromeDriver. Here’s how I did it in Transmogrifier, my Python script that helps me assemble the Tampa Bay Tech Events list:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
// 1
option = Options()
option.binary_location='/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta'
// 2
driver = webdriver.Chrome(service=Service(ChromeDriverManager(version='104.0.5112.20').install()), options=option)
Here are some explanation that match the number comments in the code above:
Options
class, which we’re using to specify the directory where the Chrome beta app can be found. We’ll use the instance, options
, when we create driver
, the object that controls the Chrome beta app.WebDriver.Chrome
object which will control the Chrome beta app. The service
parameter specifies that the driver should be an instance of ChromeDriver 104, and that it should be installed if it isn’t already present on the system. The options
parameter specifies that ChromeDriver should drive the version of Chrome located at the directory path specified in the option
object: the Chrome beta app.Once that’s done, I can proceed with my script. Here’s a simplified version of the start of my Transmogrifier script:
from bs4 import BeautifulSoup
// Load the web page whose URL is `url` into
// the browser under script control
driver.get(url)
// Execute any scripts on the page so that
// we can scrape the final rendered version
html = driver.execute_script('return document.body.innerHTML')
// And now it’s time to scrape!
soup = BeautifulSoup(html, 'html.parser')
// ...the rest of the code goes here...
Hope this helps!