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:
Big takeaways from the video:
Research the founders.
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 for numbers.
Ask questions like:
- How much runway do they have? Runway is how long they can stay in operation if their income and expenses stay the same. In an early-stage startup that doesn’t have any customers yet, runway effectively becomes how many months the company can operate before running out of money.
- What’s the burn rate? In the context of startups that raised money in order to get started, a company’s burn rate is the rate that the company is spending that money while it’s not yet making money from its operations. Fast was said to have a burn rate of $10 million per month.
- How much revenue is the company generating? Revenue is the money that the company makes from normal business operations, that is, the money they make from selling either stuff or services to its customers. Fast’s revenue for all of 2021 was about $600,000, which averages to $50,000 a month. Contrast this with their burn rate above.
- Find out if there’s a clear set of critical business metrics that they track and if they’re available to you. Any startup worth the effort is painfully and continuously aware of the key metrics that determine whether they’re doing the right things or not. The employees at Fast were unaware of how little revenue the company was making or how few customers they had
Other hints
- Interview your future manager and a founder.
- Talk to investors.
- Talk to people who left.
- Assume your stock grants are worthless.
- Remember that reward is often proportional to risk.
- Watch for worrisome numbers, including…
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
- Swift’s
Set
requires you to specify the type of things that it will store. In this case, we want to store items of typeCharacter
. - When looping through the items in a string with a
for
loop in Swift, you getCharacter
items. That’s whypreviouslyEncounteredCharacters
storesCharacter
items and notString
items. Once the function detects the first recurring character, it converts that character into a string and returns that value.
Previously in this series
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:
- 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.
Want to find out more?
- Check out the StartupBus site
- My post, I’m going on StartupBus again, and you should too!
Want to join the bus? Drop me a line!
This week’s events
Monday, July 4
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 |
Tuesday, July 5
Wednesday, July 6
Thursday, July 7
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 |
Friday, July 8
Saturday, July 9
Sunday, July 10
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 |
Do you have any events or announcements that you’d like to see on this list?
Let me know at joey@joeydevilla.com!
Join the mailing list!
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!
The ChromeDriver 103 bug
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.
The fix
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:
- These lines create an instance of the
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 createdriver
, the object that controls the Chrome beta app. - This constructor creates a
WebDriver.Chrome
object which will control the Chrome beta app. Theservice
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. Theoptions
parameter specifies that ChromeDriver should drive the version of Chrome located at the directory path specified in theoption
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!
The title of this post should be a big hint: Everything you need to know in order to win StartupBus North America 2022 is contained within a podcast. This is the third in a series of posts covering the “Startup Bus” series of episodes from Gimlet Media’s Startup podcast, which covered the New York bus’ journey during StartupBus 2017.
Did you miss the first four articles in this series? Here they are:
I’m posting this series as a prelude to StartupBus 2022, which takes place at the end of July. I was a contestant — a buspreneur — on the Florida bus in 2019, which made it all the way to the finals and finished as a runner-up. Now I’m a coach — a conductor — on the 2022 edition.
Here’s episode 5 of the podcast series…
…and here are the lessons I took away from this episode:
- A lot of what makes success is just showing up. At the start of the episode, podcast host Eric goes for an early morning walk with Colleen Lavin of team Daisy and discovers that she was nce the Illinois Knights of Columbus free throw champion for girls age 14. Here’s how she tells the story:
COLLEEN: I was like getting my school volunteer hours, helping my dad at the free throw contest, and I was in the right age range, so he made me compete. I made two baskets, because I was not a basketball player. But no other girls in my age range showed up, and he made me go to the next competition and no other girls my age range showed up. Finally, I was almost sent to D.C to compete in the nationals after making a total of like four baskets.
ERIC: Because nobody had showed up?
COLLEEN: In my age competition!
- Be prepared for possible twists in the finals. Elias Bizannes, the creator of StartupBus, loves drama. In the 2017 competition, even though there were five finalists, Elias decided to create a sixth team made up of people from teams who didn’t make it into the finals. The team would create a blockchain-powered voting app. Why did he do it? In his own words…
To mess with people to be honest. Because that’s what we do with StartupBus, we push them and we break them. And what happens is this remarkable thing comes out when people go beyond the limits they think they can, they actually step up. And so by introducing a new team, it was gonna add another level of competitive threat to the finals.
- The finals will feature far more polished pitches and apps: “From the moment the pitches begin, it’s apparent. This is a very different level of competition than yesterday. The presentations are all well-crafted. Each of the products makes sense. You could imagine people making these pitches to actual investors.”
Are you interviewing for job that involves coding or requires coding skills? Then it’s very likely that you’ll be asked to undergo a coding test in the interview.
A long while back, I very badly embarrassed myself in an interview with Google. A Googler friend referred me (referrals are always better than applying yourself) and a handful of days later, I was in the interview, and I did everything wrong. I promised myself that I would never embarrass myself with such a pitiful coding performance at an interview again, and I’d also like to help ensure that it never happens to you either.
The trick, of course, is to practice. In this series, How to solve coding interview questions, I’ll walk you through the sort of questions that you might be asked in a coding interview. Many of the questions you’ll be asked will involve the sort of things that get covered in a “Algorithms and data structures” class and will be designed to test your general problem-solving ability. I’ll show you a solution, and where applicable, I’ll show you some alternate solutions and discuss the pros and cons of each.
You should try coming up with your own answers before looking at mine — after all, it’s the best way to learn!
The “first recurring character” function
This is a classic coding interview question that is often presented to junior developers.
The challenge
Write a Python function named first_recurring_character()
or a JavaScript function named firstRecurringCharacter()
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 are some example inputs for first_recurring_character()
, along with what their corresponding outputs should be:
If you give the function this input… | …it will produce this output: |
'abcdeefg' | 'e' |
'abccddee' | 'c' |
'abcde' | null / None / nil |
One solution
See if you can code it yourself, then scroll down for my solution.
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
👇🏽
If you had to perform the function’s job yourself, you’d probably go through the given string character by character and use a piece of paper to jot down the keep track of the characters you’ve already seen.
Here’s a solution that takes this approach, in Python:
def first_recurring_character(text):
previously_encountered_characters = []
for character in text:
if character in previously_encountered_characters:
return character
else:
previously_encountered_characters.append(character)
return None
Here’s the JavaScript version:
function firstRecurringCharacter(text) {
let previouslyEncounteredCharacters = []
for (const character of text) {
if (previouslyEncounteredCharacters.includes(character)) {
return character
} else {
previouslyEncounteredCharacters.push(character)
}
}
return null
}
Both do the following:
- They use a built-in data structure to keep track of characters that they have previous encountered as they go through the given string character by character. In the Python version, the data structure is a list named
previously_encountered_characters
; in the JavaScript version, it’s an array namedpreviouslyEncounteredCharacters
. - The use a loop to go through the given string one character at a time.
- For each character in the given string, the program checks to see if the current character has been encountered before:
- If the current character has been encountered before, it’s the first repeated character. The function returns the current character.
- If the current character has not been encountered before, it is added to the data structure of previously encountered characters.
- If the function goes through the entire string without encountering a previously encountered character, it returns a null value (
None
in Python,null
in JavaScript).
What’s the Big O?
If you’ve made it this far, you might be asked how you can improve the code. This is a different question in disguise: You’re actually being asked if you know the computational complexity or “The Big O” for your solution.
First, there’s the for
loop. For a given string of length n, the worst-case scenario — either the string doesn’t have any recurring characters or the recurring character is at the very end — the loop will have to execute n times. That task’s complexity of O(n).
Next, let’s look inside the for
loop. There’s a test to see if the current character is in the collection of previously encountered characters. In Python, this test is performed by the in
operator; in JavaScript, it’s performed by the includes()
method.
- Python’s TimeComplexity page says that using the in operator to find an item in a list is an O(n) operation on average.
- The spec for JavaScript’s
includes()
method shows that it searches through an array one element at a time, which makes it an O(n) operation on average.
That’s because they both use the following algorithm to determine if a given item is in a list or array:
if we are not yet past the last item in the list/array:
get the next item in the list/array
if this item is the one we’re looking for:
return true
if we are at this point and we have not found the item:
return false
So the function is basically an O(n) operation performing an O(n) operation on average, effectively making it an O(n2) operation. As far as computational complexity goes, this is considered “horrible”:
Can you improve the code?
You’ve probably figured out that the way to improve the code is to try and reduce its time complexity.
You probably can’t reduce the time complexity of the for
loop. The function has to find the first recurring character, which means that it needs to go through the characters in the given string in order, one at a time. This part of the function will be stuck at O(n).
But you might be able to reduce the time complexity of check to see if the current character in the loop has been encountered before. In the function’s current form, we’re using a Python list or JavaScript array to keep track of characters that we’ve encountered before. Looking up an item in in these structures is an O(n) operation on average.
The solution is to change the data structure that keeps track of previously encountered characters to one where looking for a specific item is faster than O(n). Luckily, both Python and JavaScript provide a data structure for sets, where the time to look up an item is generally O(1).
Let’s rewrite the function to use sets. Here’s the Python version:
def first_recurring_character(text):
previously_encountered_characters = set()
for character in text:
if character in previously_encountered_characters:
return character
else:
previously_encountered_characters.add(character)
return None
The Python version doesn’t require much changing. We simply changed the initial definition of previously_encountered_characters
from an empty array literal ([]
) to a set
constructor and call on set’s add()
method instead of the append()
method for arrays.
Here’s the JavaScript version:
function firstRecurringCharacter(text) {
let previouslyEncounteredCharacters = new Set()
for (const character of text) {
if (previouslyEncounteredCharacters.has(character)) {
return character
} else {
previouslyEncounteredCharacters.add(character)
}
}
return null
}
The JavaScript version requires only a little more changing:
- The initial definition for
previouslyEncounteredCharacters
was changed to aSet
constructor. - We changed the array
includes()
method to the sethas()
function. - We also changed the array
push()
method to the setadd()
method.
Changing the data structure that stores the characters that we’ve encountered before reduces the complexity to O(n), which is much better.
Coming up next
In the next article in this series, we’ll tackle a slightly different problem: Can you write a function that returns the first non-recurring character in a string?