💡 Multiplication updates last_num by multiplying with current_num.
traverse
Update current_op and reset current_num
Update current_op to end marker '#' and reset current_num to 0.
💡 Resetting current_num prepares for any further processing; current_op updated to end marker to indicate no more operators.
Line:current_op = c
current_num = 0
💡 Operator updated to end marker; current_num reset.
reconstruct
Add last_num to total to get final result and return
Add last_num (4) to total (3) to compute final answer 7 and return it.
💡 Final addition combines all processed parts into the result and returns it.
Line:total += last_num
return total
💡 Final result is sum of total and last_num after all operations.
def calculate(s: str) -> int:
s = s.replace(' ', '') # STEP 1
total = 0 # STEP 1
last_num = 0 # STEP 1
current_num = 0 # STEP 1
current_op = '+' # STEP 1
for i, c in enumerate(s): # STEP 2-9
if c.isdigit(): # STEP 2,4,6
current_num = current_num * 10 + int(c) # STEP 2,4,6
if c in '+-*/' or i == len(s) - 1: # STEP 3,5,7
if current_op == '+': # STEP 3,5
total += last_num # STEP 3,5
last_num = current_num # STEP 3,5
elif current_op == '-': # Not used in this example
total += last_num
last_num = -current_num
elif current_op == '*': # STEP 7
last_num = last_num * current_num # STEP 7
elif current_op == '/': # Not used in this example
if last_num < 0:
last_num = -(-last_num // current_num)
else:
last_num = last_num // current_num
current_op = c # STEP 8
current_num = 0 # STEP 8
total += last_num # STEP 9
return total # STEP 9
if __name__ == '__main__':
print(calculate("3+2*2")) # Output: 7
📊
Basic Calculator II (No Parentheses) - Watch the Algorithm Execute, Step by Step
Watching this step-by-step helps you understand how operator precedence is handled without a stack, by tracking the last number and total separately.
Step 1/9
·Active fill★Answer cell
no_op
Stack (top→bottom)
empty
no_opElement[0]: 3
Stack (top→bottom)
empty
pushElement[1]: +
Stack (top→bottom)
3
↑ pushed: 3
no_opElement[2]: 2
Stack (top→bottom)
3
pushElement[3]: *
Stack (top→bottom)
2
3
↑ pushed: 2
no_opElement[4]: 2
Stack (top→bottom)
2
3
popElement[5]: 2
Stack (top→bottom)
4
3
↓ popped: [2]
no_opElement[5]: 2
Stack (top→bottom)
4
3
no_op
Stack (top→bottom)
7
Contributes: 7
Key Takeaways
✓ The algorithm handles operator precedence by tracking the last number separately from the total.
This is hard to see from code alone because it uses variables instead of an explicit stack, but the visualization shows how multiplication updates last_num before adding to total.
✓ Operators trigger processing of the previously accumulated number with the previous operator's logic.
Seeing each operator cause an update clarifies why the algorithm waits until an operator or end to process numbers.
✓ At the end, adding last_num to total finalizes the calculation, combining all intermediate results.
This final step is crucial and often overlooked when reading code, but the visualization highlights its importance.
Practice
(1/5)
1. You are given a list of tokens representing an arithmetic expression in postfix notation, where each token is either an integer or an operator (+, -, *, /). Which algorithmic approach guarantees an optimal and straightforward evaluation of this expression?
easy
A. Dynamic programming approach that stores intermediate results in a table indexed by token positions.
B. Greedy algorithm that evaluates tokens from left to right, applying operators as soon as possible without using extra data structures.
C. Stack-based iterative evaluation that pushes operands and applies operators by popping the last two operands from the stack.
D. Recursive backtracking that tries all possible ways to parenthesize the expression and selects the correct evaluation.
Solution
Step 1: Understand the problem structure
Postfix expressions require operands to be processed before operators, which naturally fits a stack structure.
Step 2: Identify the correct approach
Stack-based iterative evaluation pushes operands and pops two operands when an operator is encountered, applying the operator and pushing the result back.
Final Answer:
Option C -> Option C
Quick Check:
Stack usage matches postfix evaluation logic [OK]
Hint: Postfix evaluation naturally uses a stack [OK]
Common Mistakes:
Thinking greedy evaluation without stack works
Confusing postfix with infix DP
Using recursion without clear base cases
2. Given the following Python function to find previous smaller elements, what is the output when the input array is [3, 7, 1]?
def previous_smaller_element_indexes(arr):
stack = []
result = []
for i, num in enumerate(arr):
while stack and arr[stack[-1]] >= num:
stack.pop()
if stack:
result.append(arr[stack[-1]])
else:
result.append(-1)
stack.append(i)
return result
print(previous_smaller_element_indexes([3, 7, 1]))
easy
A. [-1, -1, -1]
B. [-1, 3, -1]
C. [-1, 3, 3]
D. [3, -1, -1]
Solution
Step 1: Trace iteration i=0, num=3
Stack empty, append -1 to result, push index 0 -> stack=[0], result=[-1]
Step 2: Trace iteration i=1, num=7
Stack top index 0 -> arr[0]=3 < 7, so append 3 to result, push index 1 -> stack=[0,1], result=[-1,3]
Step 3: Trace iteration i=2, num=1
Pop while arr[stack[-1]] >= 1: arr[1]=7 >=1 pop, arr[0]=3 >=1 pop, stack empty, append -1, push index 2 -> stack=[2], result=[-1,3,-1]
Final Answer:
Option B -> Option B
Quick Check:
Output matches expected previous smaller elements for each position [OK]
Hint: Pop all >= current to find closest smaller on left [OK]
Common Mistakes:
Not popping equal or greater elements leads to wrong result
Appending wrong element from stack top
Off-by-one errors in indexing
3. What is the time complexity of the optimal stack-based decoding algorithm for a string of length n with maximum repeat count max_k?
medium
A. O(n * max_k)
B. O(n)
C. O(n^2)
D. O(n log max_k)
Solution
Step 1: Identify loops and string expansions
The algorithm iterates over n characters, but each decoded substring can be repeated up to max_k times, causing repeated concatenations.
Step 2: Analyze string multiplication cost
Multiplying substrings by count k can cause up to O(n * max_k) time in worst case, as repeated expansions dominate.
Final Answer:
Option A -> Option A
Quick Check:
Repeated expansions cause linear times max_k complexity [OK]
Hint: String repeats multiply runtime by max_k [OK]
Common Mistakes:
Assuming O(n) ignoring repeat expansions
Confusing max_k with log factor
4. Consider this buggy version of the decodeString function. Which line contains the subtle bug that causes incorrect decoding for inputs with multiple bracketed substrings?
medium
A. Line appending current_string to string_stack
B. Line popping count from count_stack
C. Line resetting k after '[' is missing
D. Line appending characters to current_string
Solution
Step 1: Identify where repeat count is reset
After pushing k to count_stack on '[', k must be reset to 0 to avoid carryover to next substring.
Step 2: Locate missing reset
The code comment indicates missing reset of k after pushing it, causing subsequent repeats to accumulate incorrectly.
Final Answer:
Option C -> Option C
Quick Check:
Resetting k prevents repeat count carryover bugs [OK]
Hint: Repeat count must reset after pushing to stack [OK]
Common Mistakes:
Forgetting to reset repeat count after '['
Mismanaging stack push/pop order
5. Suppose the problem is modified so that the input string can contain not only '(' and ')' but also '*' characters, where '*' can represent either '(' or ')' or an empty string. Which approach is best suited to handle this variant efficiently?
hard
A. Use dynamic programming to track valid substring lengths considering '*' as wildcards.
B. Use the two-pass counter approach ignoring '*' characters.
C. Use brute force checking all substrings and validating with '*' replacements.
D. Use a stack-based approach tracking indices and possible '*' substitutions.
Solution
Step 1: Understand the complexity introduced by '*'
The '*' character can represent multiple possibilities, requiring tracking multiple states.
Step 2: Evaluate approaches for handling wildcards
Dynamic programming can efficiently track valid substring lengths considering '*' as '(', ')' or empty, unlike counters or naive stack approaches.
Step 3: Rule out brute force due to exponential possibilities
Brute force checking all substrings with '*' replacements is infeasible for large inputs.