Real example: Leetcode 665
Knowing interview principles is one thing. Applying them under pressure is another. To show you
Knowing interview principles is one thing. Applying them under pressure is another. To show you how the Five Keys transform a good candidate into a great one, let's walk through a real-world interview problem together:LeetCode 665: Non-decreasing Array.
The Problem: Given an array of integers nums, your task is to check if it could become non-decreasing by modifying at most one element. An array is non-decreasing if for all i where 0 <= i <= n-2, nums[i] <= nums[i+1].
Now, let's solve this, not like we're just trying to get a green checkmark on LeetCode, but like we're in a real interview at a top tech company.
Before writing a single line of code, I need to understand the boundaries of the problem. This shows I am careful and consider the details before acting.
"Thanks for the problem. I have a few clarifying questions to make sure I fully understand the scope:
true. This is a great edge case to confirm.)By asking these questions, I've already demonstrated a professional mindset and identified key edge cases to test later.
Now I'll outline my plan to the interviewer before I get lost in the code.
"Okay, so my goal is to find out if the array can be sorted with at most one change. This means the array can have at most one "dip" or "inversion," where nums[i] > nums[i+1].
I can iterate through the array with a single pass, keeping track of how many modifications I've made. I'll need a variable, let's call it modifications, initialized to zero.
When I find a dip at index i (where nums[i] > nums[i+1]), I've found a problem. I must use my one allowed modification right here to fix it. So, I'll increment my modifications counter. If I ever find a second dip, I know it's impossible, so I can immediately return false.
The tricky part is how to make the modification. When I find that nums[i] > nums[i+1], I have two choices:
nums[i]: Make nums[i] = nums[i+1].nums[i+1]: Make nums[i+1] = nums[i].Which one is better? Let's think about the element before the dip, at nums[i-1].
nums[i], I need to make sure the new nums[i] is still greater than or equal to nums[i-1]. This is the safer option because it's less likely to cause a problem with future elements. For example, in [3, 4, 2], if I find the dip at 4 > 2, I should change the 4 to a 2 (making it [3, 2, 2]). But wait, that doesn't work because 3 > 2. So I must check nums[i-1].nums[i] > nums[i+1]:nums[i-1]. If nums[i+1] is greater than or equal to nums[i-1] (e.g., in [3, 5, 4]), then it's safe to lower nums[i] to nums[i+1]. The array becomes [3, 4, 4], which is fine.nums[i+1] is less than nums[i-1] (e.g., in [4, 5, 2]), my only choice is to raise nums[i+1] to be equal to nums[i]. The array becomes [4, 5, 5].This logic seems sound. I'll perform this check at each dip. If my modifications count ever exceeds 1, I'll return false. If I finish the loop, it means it's possible, so I'll return true."
Now, I'll translate my thoughts into code, using clear variable names and structure.
Python
from typing import List
class Solution:
def checkPossibility(self, nums: List[int]) -> bool:
"""
Checks if an array can become non-decreasing by modifying at most one element.
"""
modifications = 0
for i in range(1, len(nums)):
# Found a "dip" where the order is broken.
if nums[i] < nums[i-1]:
modifications += 1
# If we need more than one modification, it's impossible.
if modifications > 1:
return False
# This is the key decision: which element to modify.
# If the element at i-2 is not a concern (either because it doesn't
# exist or it's small enough), we can safely lower the previous element (nums[i-1]).
# Example: [1, 4, 2] -> change 4 to 2
if i < 2 or nums[i] >= nums[i-2]:
nums[i-1] = nums[i]
# Otherwise, we must raise the current element (nums[i]).
# Example: [3, 4, 2] -> change 2 to 4
else:
nums[i] = nums[i-1]
return True
The solution I've provided runs in O(n) time because it involves a single pass through the array. The space complexity is O(1) as I'm only using a few variables. This is very efficient.
"I could have considered a brute-force approach where I try changing every single element one by one and, for each change, check if the entire array is sorted. That would be O(n^2), which would be too slow given the constraint of 10,000 elements. My current single-pass solution is much more optimal."
"Great, the code is written. Now I'd like to test it with a few examples to be sure it works."
[4, 2, 3]:i=1: nums[1] (2) < nums[0] (4). A dip! modifications becomes 1.i < 2 is true. So we lower nums[0] to 2. The array conceptually becomes [2, 2, 3].true. Correct.[4, 2, 1]:i=1: nums[1] (2) < nums[0] (4). A dip. modifications becomes 1.i < 2 is true. Lower nums[0] to 2. Array becomes [2, 2, 1].i=2: nums[2] (1) < nums[1] (2). Another dip! modifications becomes 2.modifications > 1 is now true, so we immediately return false. Correct.[3, 4, 2, 3] (from my own thinking):i=1: 4 > 3. OK.i=2: nums[2] (2) < nums[1] (4). Dip! modifications becomes 1.i < 2 is false. Check nums[i] >= nums[i-2]. nums[2] (2) is NOT >= nums[0] (3).else block: raise nums[i]. nums[2] becomes 4. Array is now [3, 4, 4, 3].i=3: nums[3] (3) < nums[2] (4). Dip! modifications becomes 2.false. Correct.The code handles the cases correctly. By walking through my own complex test case, I show a deeper level of care for quality.
By following these five keys, I didn't just solve a problem. I showcased a professional engineering process from start to finish. This is how you go from being just another candidate to being the person they know they need to hire.