How to Solve Python Coding Questions using Stack | by Leihua Ye, PhD | Towards Data Science

1
2
3
4
5
6
7
8
9
10
Powered by Play.ht
Create audio with Play.ht
Powered by Play.ht
Python is a versatile script-based programming language with a wide application in Artificial Intelligence, Machine Learning, Deep Learning, and Soft Engineering. Its popularity benefits from the various Data Types that Python stores.
Dictionary is the natural choice if we have to store key and value pairs, as in today’s Question 5. String and list are a pair of twin sisters that come together and solve string manipulation questions. Set holds a unique position as it does not allow duplicates, a unique feature that allows us to identify the repetitive and non-repetitive items. Well, tuple is the least frequently asked data type in technical interviews. Last week, a senior Data Scientist posted a coding question on Twitter, which can be easily solved via tuple. However, a lot of candidates got tripped over. I’ll write another post on the topic soon.
Data Types play an essential part in Python programming! Being able to differentiate one from another is super important for solving interview questions. In today’s post, let’s shift gears to another essential data type called Stack.
In writing this blog post, I have spent countless hours selecting the following questions and rank them in a way that is easily understandable to new programmers. Each question builds up upon the previous ones. If possible, please solve the problems in sequence.
A stack is a linear data structure that keeps elements in a Last-In/First-Out (LIFO) or First-In/Last-Out (FILO) manner (GeeksForGeeks). It means that elements last added will be popped from the stack first. We can picture a stack of plates: we always use the plate on the top that last added to the pile. Push and pop are the most fundamental operations of a stack, laying the ground for other more advanced adoptions.
In Python, there are three ways of implementing a stack: using a list, collections.deque, and linked list. To prepare for Data Science Interviews, the first approach is sufficiently good enough. In case you are interested in the other two, please check this post (link).
In Python, we can simply use a list to represent a stack. So, it has the same attributes as a list. It has two basic operations: push() and pop(). To push, or add, an element to a stack, we use the append() method. To pop, or delete, the last element, we use the pop() method, as follows.
stack = []          # create an empty stackstack.append(‘a’)   # push 'a' to the stackstack.append(‘b’)   # push 'b' to the stackstack.append(‘c’)   # push 'c' to the stackprint(stack)['a', 'b', 'c']stack.pop()         #pop the last element'c'stack.pop()        #pop the last element'b'stack.pop()        #pop the last element'a'stack              #check the remaining stack[]
- Given a string S of lowercase letters, a duplicate removal consists of choosing two adjacent and equal letters, and removing them.- We repeatedly make duplicate removals on S until we no longer can.- Return the final string after all such duplicate removals have been made. It is guaranteed the answer is unique.- https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/
Facebook, Amazon, Bloomberg, and Oracle included this question. While reading the question prompt, I find the following keywords worth noting: duplicate removal, two adjacent and equal, and duplicate removals. Simply put, the question translates into removing the adjacent equal letters. The translation process is crucial to simplify the question, as a lot of times, the prompt contains too much trivial information that distracts us from solving the problem. Also, identifying the key points and speaking them out loud keep the interviewer engaged.
To check if two letters are equal, the first thing that comes to my mind is to adopt brutal force and check for the same element at two consecutive positions. However, this method does not work as the removal process is dynamic.
Let’s say the test case is ‘abbaca.’ If using the brutal force, we would only be able to remove ‘bb’ the string but not the new combination ‘aa’ created after deleting ‘bb.’
We need a dynamic solution that checks if the newly created consecutive positions have the same element.
Fortunately, the universe offers stack!
We can create an empty stack (list) to store new elements. If the element is equal to the last element in the stack, we pop it out from the stack and don’t add the new element to the list. In other words, the simple pop operation removes two neighboring identical letters. Pretty neat! In the end, we rejoin the list to an empty string, a common transformation tactic.
'ca'
As a warm-up, I intentionally choose this question for its simplicity. The following questions may look slightly challenging but totally solvable following the same process.
- Given a string s of lower and upper case English letters.- A good string is a string which doesn’t have two adjacent characters s[i] and s[i + 1] where: 0 <= i <= s.length-2- s[i] is a lower-case letter and s[i + 1] is the same letter but in upper-case or vice-versa.- To make the string good, you can choose two adjacent characters that make the string bad and remove them. You can keep doing this until the string becomes good.- Return the string after making it good. The answer is guaranteed to be unique under the given constraints.- Notice that an empty string is also good.- https://leetcode.com/problems/make-the-string-great/
Google asked this question. Let’s scan the prompt again and retrieve the key information. Here are the eye-catching keywords: two adjacent characters, one in lower-case and the next is in upper-case (vice-versa), remove two adjacent characters of different cases. Simply, the question wants us to remove two adjacent characters of different cases (one upper and one lower, regardless of positions).
Remember to speak out your mind and let your interviewer know you have captured the key information. If you don’t, your interviewer will ask for justifications why you decide to adopt stack but not other data types.
Following the same logic as Question 1, we create an empty stack to store elements and check if the to-be-added letter is the same but of a different case. In Python, there are different ways of checking cases. If you don’t know any built-in method/function, like me, we can follow the following steps: first make sure these two letters are not the same (stack[-1] != i) and second they become the same after using the lower method (stack[-1].lower() ==i.lower()).
Here is a catch. We can’t pop an element from an empty stack. It would generate an index error. Like the following:
IndexError
To avoid the error message, we have to ensure the stack is not empty using if stack in line 4. This is one of the most common mistakes that Python programmers make while using a stack.
'leetcode'
As it turns out, Python has a built-in method, swapcase(), that switches letters from upper case to lower case, vice versa. Also, you may want to check with the interviewer if you can use any built-in method. Keep communicating!
'leetcode'
- Given an array target and an integer n. In each iteration, you will read a number from list = {1,2,3..., n}.- Build the target array using the following operations: — Push: Read a new element from the beginning list, and push it in the array. — Pop: delete the last element of the array. — If the target array is already built, stop reading more elements.- Return the operations to build the target array. You are guaranteed that the answer is unique.- https://leetcode.com/problems/build-an-array-with-stack-operations/
Google asked this question. This question is so user-friendly, and it explicitly tells you to push and pop elements. A stack is in order!
Creating an empty stack and iterate over the list: pushing elements to the new stack and popping the last element. Lastly, check if the constructed array is the same as the target array. If so, stop the iteration.
The only catch is to break the for loop if we have obtained the target array. To do so, keep the indentation block of stack==target (line 16 & 17) in line with the if-else statement. Interviewers may likely ask follow-up questions about why you keep the indentation inside the for loop rather than outside.
['Push', 'Push', 'Pop', 'Push']
- You are keeping score for a baseball game with strange rules. The game consists of several rounds, where the scores of past rounds may affect future rounds’ scores.- At the beginning of the game, you start with an empty record. You are given a list of strings ops, where ops[i] is the ith operation you must apply to the record and is one of the following:- An integer x — Record a new score of x. — “+” — Record a new score that is the sum of the previous two scores. It is guaranteed there will always be two previous scores. — “D” — Record a new score that is double the previous score. It is guaranteed there will always be a previous score. — “C” — Invalidate the previous score, removing it from the record. It is guaranteed there will always be a previous score.- Return the sum of all the scores on the record.- https://leetcode.com/problems/baseball-game/
Amazon picked this question. This is another interviewee-friendly question as it tells you to push and pop elements. Also, we need to use a control flow using multiple if statements. The procedure of building a stack and adding/removing elements is the same as the above questions. Here, I focus on the unique attribute of this question that needs special attention.
Usually, we have to check if a stack is empty or not before popping elements, as in Question 2. However, we don’t have to check for this question because the prompt tells us that there will always be a previous score. Without the extra condition, the question becomes slightly messier. In the end, we use a sum() function to return the sum of all the scores.
Problem solved!
30
- You are given two integer arrays nums1 and nums2 both of unique elements, where nums1 is a subset of nums2.- Find all the next greater numbers for nums1’s elements in the corresponding places of nums2.- The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, return -1 for this number.- https://leetcode.com/problems/next-greater-element-i/
Amazon and Blooomberg picked this question. Question 5 requires more than a 2-step solution. But first, the eye-catching keywords include: nums1 is a subset of nums2, find the next greater numbers for nums1 in nums2, and return -1 for none.
In my mind, here is the translation process:
#1 subset → elements in nums1 should also be in nums2. #2 find the next greater numbers → positions matter and value matters! # 3 return -1 if such value does not exist → Use if-else statement as a control flow.
Taken together, we have to find a way of identifying the position and value of an element and use if-else statements to compare values.
To find the position and value of an element, the natural choice is to use the enumerate() function. Also, we want to use a dictionary to keep records of the key-value pairs.
Next, we iterate over the array nums2 and find the next greater item. If there is such an item, we break the for loop; otherwise, return -1. The complete code is in Solution 1.
This approach makes intuitive sense, and it’s easy to follow.
 [-1, 3, -1]
Disclaimer: Solution 2 is not my original code, and special credits go to aditya baurai’s post.
As it turns out, we can adopt a stack and a dictionary. First, we create an empty stack/dictionary and iterate over nums2:
#1 if the stack is not empty and the last stack element is smaller than num: we pop the stack and create a key-value pair in the dictionary.#2 for other cases, we append the element to the stack.
To clarify, the for loop iterates over all of the elements in nums2, and the while loop is to find the next greater element in nums2 compared to the stack. To better help us understand, we can loop over the first 2 elements of nums2.
# pseudo code# nums2: [1,3,4,2]# step 1: # when the first element num == 1for num in nums2:     stack.append(num) # since the stack is empty# step 2: for the second element num ==3for num in nums2:     # since the stack isn't empty    while stack and stack[-1] <num:        anum = stack.pop() # pop out the last element 1 # create a key-value pair: 1 is the key and 3 is the value        and[anum] = num
In brief, the above code finds all of the greater elements in nums2, and then we find the corresponding value for elements in nums1 in the end.
[-1, 3, -1]
The complete Python code is available on my Github.
Stack has two operations: push() and pop().
Identify the keywords and communicate with your interviewer.
Stack often teams up with the following keywords: two consecutive identical letters/numbers/words, push and pop an element if it is related somehow to the previous position.
Check if it is an empty stack before popping.
Indentation is crucial for loops. Understand the question well and decide its position (inside or outside the loop).
Complicated coding questions can be disaggregated into multiple smaller pieces.
Medium recently evolved its Writer Partner Program, which supports ordinary writers like myself. If you are not a subscriber yet and sign up via the following link, I’ll receive a portion of the membership fees.
leihua-ye.medium.com
towardsdatascience.com
towardsdatascience.com
towardsdatascience.com
Please find me on LinkedIn and Youtube.
Also, check my other posts on Artificial Intelligence and Machine Learning.