String Methods
Python has dozens of string methods, but you only need about ten of them for coding interviews. Here they are in one place:
The rest of this page goes through each one and points out the mistakes people tend to make with them.
isalnum(), isalpha(), and isdigit()
O(n)These check what kind of characters a string holds. They're most useful on a single character while you loop through a string:
Valid Palindrome is the classic place you'll need isalnum(). The problem tells you to ignore anything that isn't a letter or a digit, and this is how you skip those characters:
Note
"-5".isdigit() is False, and so is "3.14".isdigit(), because the minus sign and the dot aren't digits. If you need to know whether a string is any kind of number, try int(s) or float(s) inside a try/except ValueError instead.
ord() and chr() for character math
O(1)ord() turns a character into its number, and chr() turns a number back into a character. Letters are in order, so ord(c) - ord("a") gives you 0 for "a", 1 for "b", and so on up to 25:
That trick lets you count letters with a plain list of 26 slots instead of a dict. It comes up a lot in anagram problems:
You can go the other way to shift letters, like in a Caesar cipher:
split() and join()
O(n)split() breaks a string into a list, and join() does the opposite. You'll use them together all the time, like when you need to reverse the words in a sentence:
The thing that trips people up is that split() and split(" ") don't do the same thing. With no argument, Python splits on any amount of whitespace and drops empty pieces. With " ", it splits on every single space, so extra spaces leave empty strings behind:
Note
join() is called on the separator, not the list. So it's ", ".join(items), not items.join(", "). Every item also has to be a string already, so a list of numbers needs " ".join(map(str, nums)).
strip(), lower(), and upper()
O(n)strip() removes whitespace from both ends. lstrip() and rstrip() only do one side. You can also pass the characters you want gone:
lower() and upper() are how you make a comparison ignore case. Lowercase both sides before you compare them:
Note
None of these change the original string. They all return a new one, so s.strip() on its own line does nothing useful. You have to write s = s.strip().
Strings are immutable, so build with a list
O(n) vs O(n²)You can't change a character in a string. Trying to assign to an index raises an error:
To change characters, turn the string into a list, edit the list, and join it back into a string:
Immutability also matters when you build a string in a loop. Every += can make a brand new copy of the whole string so far, and that can add up to O(n²) time. Appending to a list and joining once at the end is O(n):
Note
CPython sometimes optimizes += on strings so it isn't actually slow, but you can't count on that, and interviewers know the list-and-join pattern. Using it shows you understand why it matters.
Reversing a string with [::-1]
O(n)Strings don't have a reverse() method. Instead, you use a slice with a step of -1, which walks the string from the back:
This is the same slicing you use on lists. The list slicing page explains how start:stop:step works if the syntax looks strange.
find() vs index()
O(n·m)Both give you the position of the first match. They only differ when there's no match. find() returns -1, and index() raises an error:
If you only need to know whether a substring is there, skip both and use in. It reads better:
Note
Be careful with if s.find(x):. A match at index 0 returns 0, which is falsy, and a miss returns -1, which is truthy. That's backward from what you want. Compare against -1 or just use in.
count()
O(n)count() tells you how many times a substring shows up. Matches don't overlap, which can surprise you:
If you need counts for every character, don't call count() once per letter. That scans the whole string each time. One pass with a 26-slot list or a Counter is faster.
replace(), startswith(), and endswith()
O(n)You probably won't need these in an interview, but they're handy to know. replace() swaps every match by default. Pass a third argument if you only want to replace the first few:
startswith() and endswith() save you from slicing and comparing by hand. They also take a tuple if any of a few options is fine: